module y4d_draw.surface;

private import std.c.stdlib; // qsort

private import SDL;
private import SDL_image;

private import ytl.y4d_result;

private import y4d_aux.filesys;
private import y4d_aux.cacheobject;

private import y4d_draw.drawbase;

//private import SDL_RWops;

///	描画のためのサーフェース
/**
	2D描画、3D描画のときに用いられる、サーフェース。
	bmp,png等の読み込み/書き出しをサポート。
*/
class Surface : ICacheObject {

	this() {}
	
	
	///	サーフェースへの画像読み込みメソッド
	/**
		bmp画像,png画像を読み込みサポート。
		読み込み失敗のときは非0が返る。
	*/
	y4d_result		load(char[] filename){
		
		scope FileSys.RWops rw = FileSys.readRW(filename);

		if(rw.rwops) {
			scope void[] data = rw.data.dup;
			rw.data = data;
			rw.rwops = SDL_RWFromMem(&data[0],data.length);

			surface = IMG_Load_RW(rw.rwops,0);
				//	0 mean is will not automatically close/free the src

			if (surface !is null) {
				SDL_RWclose(rw.rwops);
				return y4d_result.no_error; // success
			}
			
			//	RWopsは生きているので他の読み込み方法をトライすべき..

			SDL_RWclose(rw.rwops);
			return y4d_result.file_read_error ; // at last,can't be identified

		} else if (rw.filename) {
			surface = IMG_Load(std.string.toStringz(filename));

			if (surface) {
				return y4d_result.no_error; // success
			}
			return y4d_result.file_read_error ; // at last,can't be identified
		} else {
			return y4d_result.file_not_found; // file not found
		}
	}

	///	サーフェースの内容をBMP形式で保存する
	y4d_result		saveBMP(char[] filename){
		if (surface){
			return SDL_SaveBMP(surface,std.string.toStringz(filename))
				? y4d_result.SDL_error:y4d_result.no_error;
		} else {
			return y4d_result.precondition_error; // no surface
		}
	}

	///	サーフェースのサイズを取得
	void	getSize(out int x,out int y){
		if (surface) {
			x = surface.w; y = surface.h;
		} else {
			x = y = 0;
		}
	}

	/// サーフェースの幅を取得
	int getWidth() {
		if (surface)
			return surface.w;
		else
			return 0;
	}
	
	/// キャッシャブル対応のため、サイズを返す
	ulong getBufferSize() {
		if (surface !is null) {
			return surface.w * surface.h * (isAlpha ? 4 : 3);
		}
		return 0L;
	}
	
	/// 自分自身の複製を生成する
	Surface clone() {
		int width =  getWidth();
		int height = getHeight();
		bool alpha = cast(bool) (getSurface().format.BitsPerPixel==32);

		// createDIBして転送したほうがはやいんでないかな...
		Surface theSurface = new Surface();
		theSurface.createDIB( width, height, alpha );

		theSurface.blt( this, 0, 0 );
		return theSurface;
	}

	///	サーフェースの高さを取得
	int getHeight() {
		if (surface)
			return surface.h;
		else
			return 0;
	}

	///	サーフェースをクリア
	y4d_result clear() {
		if (surface)
			return SDL_FillRect(surface,null,0)
				? y4d_result.SDL_error:y4d_result.no_error;
			// surface,SDL_rect*,uint color
		return y4d_result.precondition_error;
	}

	bool isAlpha() {
		if ( surface is null ) {
			return false;
		}

		SDL_Surface* surface_ = cast( SDL.SDL_Surface* ) surface;
		SDL_PixelFormat* format = cast( SDL.SDL_PixelFormat* ) surface_.format;

		return ( format !is null && format.Amask != 0 );
		// alpha maskを持つならば、alpha channelがあるのだろう。
	}		


	///	RGB888 or RGBA8888のサーフェースを作成する。
	/**
		サーフェースサイズ(x,y)<BR>

		bAlphaがtrueのときはRGBA8888(1pixelがR,G,B,A各8bitα付き32bit)
		bAlphaがfalseのときはRGB888(1pixelがRGB各8bit,24bit)
		のサーフェースを作成する。<BR>

		失敗時には非0が返る
	*/
	y4d_result	createDIB(int x,int y,bool bAlpha){
		release();
		return createDIBstatic(surface,x,y,bAlpha);
	}

	///	createDIBのstaticバージョン
	static y4d_result createDIBstatic(out SDL_Surface* surface,
	  int x,int y,bool bAlpha){
version (LittleEndian) {
		if (bAlpha) {
			surface = SDL_CreateRGBSurface(
			SDL_SWSURFACE,
			x,y,32,
			0x000000ff,		// Rmask
			0x0000ff00, 	// Gmask
			0x00ff0000,		// Bmask
			0xff000000		// Amask
			);
		} else {
			surface = SDL_CreateRGBSurface(
			SDL_SWSURFACE,
			x,y,24,
			0x000000ff,		// Rmask
			0x0000ff00, 	// Gmask
			0x00ff0000,		// Bmask
			0x00000000		// Amask
			);
		}
} else version (BigEndian) {
		if (bAlpha) {
		surface = SDL_CreateRGBSurface(
			SDL_SWSURFACE,
			x,y,32,
			0xff000000,		// Rmask
			0x00ff0000,		// Gmask
			0x0000ff00, 	// Bmask
			0x00000000		// Amask
		);
		} else {
		surface = SDL_CreateRGBSurface(
			SDL_SWSURFACE,
			x,y,24,
			0x00ff0000,		// Rmask
			0x0000ff00,		// Gmask
			0x000000ff, 	// Bmask
			0x00000000		// Amask
		);
		}
}
		if (!surface) return y4d_result.SDL_error; // 作成失敗
		return y4d_result.no_error;
	}

	///	内部的に作成されたサーフェースがRGB888かどうかをチェックする
	/**
		RGB888ならばtrueが返る。
<PRE>
		little endianで、
			0x000000ff,		// Rmask
			0x0000ff00, 	// Gmask
			0x00ff0000,		// Bmask
		になっているの意味。
</PRE>
	*/
	bool	checkRGB888(){ return checkRGB888static(surface); }

	///	checkRGB888のstaticバージョン
	static bool	checkRGB888static(SDL_Surface* surface){
		if (!surface) return false;
		SDL_PixelFormat* format = surface.format;
		if (!format) return false;
version (LittleEndian) {
		return cast(bool) (format.BitsPerPixel == 24
			&& format.Rmask == 0x000000ff
			&& format.Gmask == 0x0000ff00
			&& format.Bmask == 0x00ff0000)
			//	Amaskに関しては条件なし
		;
} else version (BigEndian) {
		return format.BitsPerPixel == 24
			&& format.Rmask == 0x00ff0000
			&& format.Gmask == 0x0000ff00
			&& format.Bmask == 0x000000ff
		;
}
	}

	///	内部的に作成されたサーフェースがRGBA8888かどうかをチェックする
	/**
		RGBA8888ならばtrueが返る。
<PRE>
		little endianで、
			0x000000ff,		// Rmask
			0x0000ff00, 	// Gmask
			0x00ff0000,		// Bmask
			0xff000000,		// Amask
		になっているの意味。
</PRE>
	*/
	bool	checkRGBA8888(){ return checkRGBA8888static(surface); }

	///	checkRGBA8888のstaticバージョン
	static bool	checkRGBA8888static(SDL_Surface* surface){
		if (!surface) return false;
		SDL_PixelFormat* format = surface.format;
		if (!format) return false;
version (LittleEndian) {
		return cast(bool) (format.BitsPerPixel == 32
			&& format.Rmask == 0x000000ff
			&& format.Gmask == 0x0000ff00
			&& format.Bmask == 0x00ff0000
			&& format.Amask == 0xff000000)
		;
} else version (BigEndian) {
		return format.BitsPerPixel == 32
			&& format.Rmask == 0xff000000
			&& format.Gmask == 0x00ff0000
			&& format.Bmask == 0x0000ff00
			&& format.Amask == 0x000000ff
		;
}
	}

	///	SDL_Surfaceを取得する
	/**
		内部で使用しているサーフェースを取得する。
		(通常使うことはない)
	*/
	SDL_Surface* getSurface() {
		return surface;
	}

	///	SDL_Surfaceを設定する
	/**
		内部で使用しているサーフェースとして外部のSDL_Surfaceを設定する。
		(通常使うことはない)
	*/
	void	setSurface(SDL_Surface* surface_) {
		release();
		surface = surface_;
	}

	///	サーフェースの解放
	void release() {
		if (surface) {
			SDL_FreeSurface(surface);
			surface = null;
		}
	}

	///	画像の転送
	/**
		src : 転送元画像  x,y : 転送先座標<BR>

		これ以上の転送を期待しているなら、SDL gfxをportingしてくるべき。
	*/
	y4d_result blt(Surface src,int x,int y) {
		if (!surface) return y4d_result.precondition_error;
			// 転送先が構築されていない

		if (!src.surface) return y4d_result.invalid_parameter;
			// 転送元が構築されていない
		SDL_Rect dest;
		dest.x = cast(short) x;
		dest.y = cast(short) y;
		dest.w = cast(ushort) src.surface.w;
		dest.h = cast(ushort) src.surface.h;

		//	αを無効化しておかないとARGB→ARGBのbltで
		//	αを考慮して転送しやがる
		SDL_SetAlpha(src.getSurface(),0,0);

 		return SDL_BlitSurface(src.surface,null,surface,&dest)
				? y4d_result.SDL_error:y4d_result.no_error;
	}
	
	///	画像の転送
	/**
		src : 転送元画像  x,y : 転送先座標<BR>

		これ以上の転送を期待しているなら、SDL gfxをportingしてくるべき。
	*/
	y4d_result bltSrcAlpha(Surface src,int x,int y) {
		if (!surface) return y4d_result.precondition_error;
			// 転送先が構築されていない

		if (!src.surface) return y4d_result.invalid_parameter;
			// 転送元が構築されていない
		SDL_Rect dest;
		dest.x = cast(short) x;
		dest.y = cast(short) y;
		dest.w = cast(ushort) src.surface.w;
		dest.h = cast(ushort) src.surface.h;

		//	αを無効化しておかないとARGB→ARGBのbltで
		//	αを考慮して転送しやがる
		// こちらのメソッドは、転送先のアルファを変更しない
		SDL_SetAlpha(src.getSurface(),SDL_SRCALPHA,0);

 		return SDL_BlitSurface(src.surface,null,surface,&dest)
				? y4d_result.SDL_error:y4d_result.no_error;
	}

	///	画像データへのポインタを返す
	/**
		読み込まれた画像データは、RGB順にbyteで並んでいると仮定して良い。
		いわゆるRGBA8888である。

		画像が読み込まれていないときはnullが返る。
	*/
	void*	getPixels() {
		if (!surface) return null;
		return surface.pixels;
	}

	/// モーフィング
	int morphBltFast(inout Surface lpDIB32, RectInt* lpSrcRect, PointInt* lpDstPoint, RectInt* lpClip)
	{
		if (lpSrcRect is null) {
	//		lpSrcRect = lpDIB32->GetRect();
		}
		//	ＲＥＣＴ－＞ＰＯＩＮＴ変換
		PointInt	lpSrcPoint[4];
		lpSrcPoint[0].x = cast(int) lpSrcRect.left;
		lpSrcPoint[0].y = lpSrcRect.top;
		lpSrcPoint[1].x = lpSrcRect.right;
		lpSrcPoint[1].y = lpSrcRect.top;
		lpSrcPoint[2].x = lpSrcRect.left;
		lpSrcPoint[2].y = lpSrcRect.bottom;
		lpSrcPoint[3].x = lpSrcRect.right;
		lpSrcPoint[3].y = lpSrcRect.bottom;
		return morphBltFast(lpDIB32, lpSrcPoint.ptr, lpDstPoint, lpClip, false);
	}
	
	/// モーフィング
	int morphBltFast(inout Surface lpDIB32, PointInt* lpSrcPoint, RectInt* lpDstRect, RectInt* lpClip=null)
	{
		//	ＲＥＣＴ－＞ＰＯＩＮＴ変換
		PointInt	lpDstPoint[4];
		lpDstPoint[0].x = lpDstRect.left;
		lpDstPoint[0].y = lpDstRect.top;
		lpDstPoint[1].x = lpDstRect.right;
		lpDstPoint[1].y = lpDstRect.top;
		lpDstPoint[2].x = lpDstRect.left;
		lpDstPoint[2].y = lpDstRect.bottom;
		lpDstPoint[3].x = lpDstRect.right;
		lpDstPoint[3].y = lpDstRect.bottom;
	
		return morphBltFast(lpDIB32, lpSrcPoint, cast(PointInt*) lpDstPoint, lpClip, true);
	}	
		
	/// モーフィング
	int morphBltFast(inout Surface lpDIB32, PointInt* lpSrcPoint, PointInt* lpDstPoint, RectInt* lpClip, bool bContinual)
	{

	//	WARNING(m_lpdwSrc == NULL,"CDIB32P5::MorphBltFastでm_lpdwSrc == NULL");
	//	{
	//	CDIB32Base* p = lpDIB32.GetDIB32BasePtr();
	//	WARNING(p == NULL || p.GetPtr() == NULL,"CDIB32P5::MorphBltFastでp.GetPtr() == NULL");
	//	}
	
		RectInt myRc;
		//	クリップ領域変換
		if (lpClip is null) {
			myRc.setRect(0, 0, surface.w, surface.h);
			lpClip = &myRc;
		}

//printf("morphBltFast  1 - 1\n");

		//	スキャン・出力用開始点とＵＶステップバッファ
		StartAndStep lpScanSS[3];
		StartAndStep lpPutSS[3];
		//	ｌｍｎ各成分におけるスキャン側(Sx,Sy)-(Ex,Ey)を割るための出力Ｙ長さ
		int	lpnScanU[3];
		int lpnScanV[3];
		//	スキャンする４点の頂点連結バッファ
		static Point lpPointConnect[Point.POINT_NUM][3] = [
			//	 A			  B			   C			D
			[ Point.B, Point.C, Point.D ], 
			[ Point.A, Point.D, Point.C ], 
			[ Point.A, Point.D, Point.B ],
			[ Point.B, Point.C, Point.A ]
		];
		//	出力四角形の頂点Ｙ方向ソート結果格納バッファ
		DstSort	lpDstSort[Point.POINT_NUM];
		for (int i = Point.A; i < Point.POINT_NUM; i++) {
			lpDstSort[i].p = cast(Point) (i);
			lpDstSort[i].x = cast(int) (lpDstPoint + i).x;
			lpDstSort[i].y = cast(int) (lpDstPoint + i).y;
		}
		//	出力ポイントをＹ方向順にする。
		qsort(cast(void*) lpDstSort.ptr, cast(uint) Point.POINT_NUM, cast(uint) lpDstSort[0].sizeof, 
				&pointsort);
		
		//	出力するｌｍｎ成分ｙ方向カウンタバッファ
		int			lpPutCount[3];
		lpPutCount[0] = lpDstSort[1].y - lpDstSort[0].y;
		lpPutCount[1] = lpDstSort[2].y - lpDstSort[1].y;
		lpPutCount[2] = lpDstSort[3].y - lpDstSort[2].y;
		
		//	頂点出力データ読み出してセット
		lpPutSS[0].nStartX = lpDstSort[0].x;
		lpPutSS[0].nStartY = lpDstSort[0].y;
		//	頂点からのUV線求める
		Point	point0 = lpDstSort[0].p;
		Point	point1 = lpPointConnect[lpDstSort[0].p][0];
		Point	point2 = lpPointConnect[lpDstSort[0].p][1];
		int nVect = cast(int) (((lpDstPoint + point2).x - (lpDstPoint + point0).x) *
					  ((lpDstPoint + point1).y - (lpDstPoint + point0).y)) -
					(((lpDstPoint + point2).y - (lpDstPoint + point0).y) *
					 ((lpDstPoint + point1).x - (lpDstPoint + point0).x));
		Point	pointU, pointV, pointExc;
		if (0 > nVect) {
			pointV = lpPointConnect[lpDstSort[0].p][0];
			pointU = lpPointConnect[lpDstSort[0].p][1];
		} else {
			pointU = lpPointConnect[lpDstSort[0].p][0];
			pointV = lpPointConnect[lpDstSort[0].p][1];
		}
		pointExc = lpPointConnect[lpDstSort[0].p][2];
		//	最初の頂点からのｌ処理値求めてセット
		lpnScanU[0] = (lpDstPoint + pointU).y - lpDstSort[0].y;
		lpnScanV[0] = (lpDstPoint + pointV).y - lpDstSort[0].y;
		lpPutSS[0].nStepUX = lpDstSort[0].x - (lpDstPoint + pointU).x;
		lpPutSS[0].nStepVX = lpDstSort[0].x - (lpDstPoint + pointV).x;
		lpScanSS[0].nStartX = (lpSrcPoint + lpDstSort[0].p).x;
		lpScanSS[0].nStartY = (lpSrcPoint + lpDstSort[0].p).y;
		lpScanSS[0].nStepUX = lpScanSS[0].nStartX - (lpSrcPoint + pointU).x;
		lpScanSS[0].nStepUY = lpScanSS[0].nStartY - (lpSrcPoint + pointU).y;
		lpScanSS[0].nStepVX = lpScanSS[0].nStartX - (lpSrcPoint + pointV).x;
		lpScanSS[0].nStepVY = lpScanSS[0].nStartY - (lpSrcPoint + pointV).y;
		if ((lpDstSort[1].p != pointU) && (lpDstSort[1].p != pointV))
			return 0;
	
//printf("morphBltFast  2 - 1\n");
			
		//	ｍ処理値求めてセット
		if (lpDstSort[1].p == pointU) {
			lpnScanU[1] = (lpDstPoint + pointExc).y - lpDstSort[1].y;
			lpnScanV[1] = 0;
			lpPutSS[1].nStepUX = lpDstSort[1].x - (lpDstPoint + pointExc).x;
			lpPutSS[1].nStepVX = 0;
			lpScanSS[1].nStartX = (lpSrcPoint + pointU).x;
			lpScanSS[1].nStartY = (lpSrcPoint + pointU).y;
			lpScanSS[1].nStepUX = lpScanSS[1].nStartX - (lpSrcPoint + pointExc).x;
			lpScanSS[1].nStepUY = lpScanSS[1].nStartY - (lpSrcPoint + pointExc).y;
			lpScanSS[1].nStepVX = 0;
			lpScanSS[1].nStepVY = 0;
			if (lpDstSort[2].p == pointV) {
				lpnScanU[2] = 0;
				lpnScanV[2] = (lpDstPoint + pointExc).y - lpDstSort[2].y;
				lpPutSS[2].nStepUX = 0;
				lpPutSS[2].nStepVX = lpDstSort[2].x - (lpDstPoint + pointExc).x;
				lpScanSS[2].nStartX = (lpSrcPoint + pointV).x;
				lpScanSS[2].nStartY = (lpSrcPoint + pointV).y;
				lpScanSS[2].nStepUX = 0;
				lpScanSS[2].nStepUY = 0;
				lpScanSS[2].nStepVX = lpScanSS[2].nStartX - (lpSrcPoint + pointExc).x;
				lpScanSS[2].nStepVY = lpScanSS[2].nStartY - (lpSrcPoint + pointExc).y;
			} else {
				lpnScanV[2] = 0;
				lpnScanU[2] = (lpDstPoint + pointV).y - lpDstSort[2].y;
				lpPutSS[2].nStepVX = 0;
				lpPutSS[2].nStepUX = lpDstSort[2].x - (lpDstPoint + pointV).x;
				lpScanSS[2].nStartX = (lpSrcPoint + pointExc).x;
				lpScanSS[2].nStartY = (lpSrcPoint + pointExc).y;
				lpScanSS[2].nStepVX = 0;
				lpScanSS[2].nStepVY = 0;
				lpScanSS[2].nStepUX = lpScanSS[2].nStartX - (lpSrcPoint + pointV).x;
				lpScanSS[2].nStepUY = lpScanSS[2].nStartY - (lpSrcPoint + pointV).y;
			}
		} else {
			lpnScanU[1] = 0;
			lpnScanV[1] = (lpDstPoint + pointExc).y - lpDstSort[1].y;
			lpPutSS[1].nStepUX = 0;
			lpPutSS[1].nStepVX = lpDstSort[1].x - (lpDstPoint + pointExc).x;
			lpScanSS[1].nStartX = (lpSrcPoint + pointV).x;
			lpScanSS[1].nStartY = (lpSrcPoint + pointV).y;
			lpScanSS[1].nStepUX = 0;
			lpScanSS[1].nStepUY = 0;
			lpScanSS[1].nStepVX = lpScanSS[1].nStartX - (lpSrcPoint + pointExc).x;
			lpScanSS[1].nStepVY = lpScanSS[1].nStartY - (lpSrcPoint + pointExc).y;
			if (lpDstSort[2].p == pointU) {
				lpnScanV[2] = 0;
				lpnScanU[2] = (lpDstPoint + pointExc).y - lpDstSort[2].y;
				lpPutSS[2].nStepVX = 0;
				lpPutSS[2].nStepUX = lpDstSort[2].x - (lpDstPoint + pointExc).x;
				lpScanSS[2].nStartX = (lpSrcPoint + pointU).x;
				lpScanSS[2].nStartY = (lpSrcPoint + pointU).y;
				lpScanSS[2].nStepVX = 0;
				lpScanSS[2].nStepVY = 0;
				lpScanSS[2].nStepUX = lpScanSS[2].nStartX - (lpSrcPoint + pointExc).x;
				lpScanSS[2].nStepUY = lpScanSS[2].nStartY - (lpSrcPoint + pointExc).y;
			} else {
				lpnScanU[2] = 0;
				lpnScanV[2] = (lpDstPoint + pointU).y - lpDstSort[2].y;
				lpPutSS[2].nStepUX = 0;
				lpPutSS[2].nStepVX = lpDstSort[2].x - (lpDstPoint + pointU).x;
				lpScanSS[2].nStartX = (lpSrcPoint + pointExc).x;
				lpScanSS[2].nStartY = (lpSrcPoint + pointExc).y;
				lpScanSS[2].nStepUX = 0;
				lpScanSS[2].nStepUY = 0;
				lpScanSS[2].nStepVX = lpScanSS[2].nStartX - (lpSrcPoint + pointU).x;
				lpScanSS[2].nStepVY = lpScanSS[2].nStartY - (lpSrcPoint + pointU).y;
			}
		}
		//	スキャンライン中の（Ｓｘ，Ｓｙ）－（Ｅｘ，Ｅｙ）の位置と
		//	スキャンラインの変化ステップ
		int		nScanStepSX, nScanStepSY, nScanStepEX, nScanStepEY;
		int		nScanLineSX, nScanLineSY, nScanLineEX, nScanLineEY;
		int		nScanLineStepX, nScanLineStepY;
		//	出力ラインの（Ｓｘ，Ｙｎ）－（Ｅｘ，Ｙｎ）
		int		nPutStepSX, nPutStepEX;
		int		nPutLineSX, nPutLineEX;
		int		nPutLineLeng;
		//	出力バッファベースアドレス
	//	Surface	p = lpDIB32.GetDIB32BasePtr();
	
		Surface	p = lpDIB32;
	
		uint*		lpDstBase = cast(uint*)(cast(ubyte*)m_lpdwSrc + (lpPutSS[0].nStartY * m_lPitch) - m_lPitch );	
		uint*		lpSrcBase = p.m_lpdwSrc;
		uint		lSrcPitch = cast(uint) p.m_lPitch;
		uint		lDstPitch = cast(uint) m_lPitch;
		uint**		lplpLineStart = cast(uint**) p.m_lpdwLineStart;
		uint*		lpSrcEnd =	cast(uint*) ( cast(ubyte*) p.m_lpdwSrc + p.m_lPitch * m_rcRect.bottom );	
		//	スキャン・出力のクリッピング領域
		uint*		lpDstStart = cast(uint*)(cast(ubyte*)m_lpdwSrc + (lpClip.top * m_lPitch));		
		uint*		lpDstEnd = cast(uint*)(cast(ubyte*)m_lpdwSrc + (lpClip.bottom * m_lPitch));	
		uint*		lpDstLineStart = lpDstBase + lpClip.left;
		uint*		lpDstLineEnd = lpDstBase + lpClip.right;
		int			nSrcSX = p.m_rcRect.left;
		int			nSrcSY = p.m_rcRect.top;
		int			nSrcEX = p.m_rcRect.right;
		int			nSrcEY = p.m_rcRect.bottom;
		uint		nPutLineAdj = (bContinual ? 0 : 1 << 20);
		uint		SrcClip = 0;
		//	アセンブラでのバックアップワーク
		uint		nScanPointX, nScanPointY;
	
//printf("morphBltFast  3 - 1\n");
		
		//	ｌ成分処理
			nScanStepSX = lpScanSS[0].nStepUX; //  / lpnScanU[0]
			nScanStepSY = lpScanSS[0].nStepUY; //  / lpnScanU[0]
			nScanStepEX = lpScanSS[0].nStepVX; //  / lpnScanV[0]
			nScanStepEY = lpScanSS[0].nStepVY; //  / lpnScanV[0]
			nScanLineSX = lpScanSS[0].nStartX;
			nScanLineSY = lpScanSS[0].nStartY;
			nScanLineEX = lpScanSS[0].nStartX;
			nScanLineEY = lpScanSS[0].nStartY;
			nPutStepSX = lpPutSS[0].nStepUX;	// / lpnScanU[0]
			nPutStepEX = lpPutSS[0].nStepVX;	// / lpnScanV[0]
			if (lpPutCount[0]) {
				nPutLineSX = lpPutSS[0].nStartX;
				nPutLineEX = lpPutSS[0].nStartX;
			} else {
				nPutLineSX = lpPutSS[0].nStartX;
				nPutLineEX = lpPutSS[0].nStartX - lpPutSS[0].nStepVX;
			}
	
//printf("morphBltFast  3 - 2\n");
			
			asm {
				sal		nPutLineSX,20			;
				mov		EDI,lpDstBase			;
	
				sal		nPutLineEX,20			;
				mov		ESI,lpSrcBase			;
				////////////////////////////////
				or		lpnScanU[0],0			;
				jz		conv_skip5				;
				
				//	データの固定小数変換
				mov		EAX, nScanStepSX		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[0]				;
				mov		nScanStepSX, EAX		;
				///////////////////////////////
				mov		EAX, nScanStepSY		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[0]				;
				mov		nScanStepSY, EAX		;
				//////////////////////////////
				sal		nScanLineSX,20			;
				sal		nScanLineSY,20			;
				/////////////////////////////
				mov		EAX,nPutStepSX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[0]				;
				mov		nPutStepSX,EAX			;
	conv_skip5:									;
				or		lpnScanV[0],0			;
				jz		conv_skip6				;
				///////////////////////////////
				mov		EAX,nScanStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[0]				;
				mov		nScanStepEX, EAX		;
				///////////////////////////////
				mov		EAX,nScanStepEY			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[0]				;
				mov		nScanStepEY,EAX			;
				//////////////////////////////
				sal		nScanLineEX,20			;
				sal		nScanLineEY,20			;
				////////////////////////////
				mov		EAX,nPutStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[0]				;
				mov		nPutStepEX,EAX			;
	conv_skip6:									;
				or		lpPutCount[0],0			;
				jz		end_ly1					;
				//	ｙ方向ループ
	loop_ly1:									;
				//	スキャン開始終了位置更新
				mov		EAX,nScanStepSX			;
				mov		EBX,nScanLineSX			;
	
				mov		EDX,nScanStepSY			;
				sub		EBX,EAX					;
	
				mov		ECX,nScanLineSY			;
				mov		nScanLineSX,EBX			;
	
				sub		ECX,EDX					;
				mov		EAX,nScanStepEX			;
				
				mov		nScanLineSY,ECX			;
				mov		EBX,nScanLineEX			;
				
				sub		EBX,EAX					;
				mov		ECX,nScanLineEY			;
				
				mov		EDX,nScanStepEY			;
				sub		ECX,EDX					;
				
				mov		nScanLineEX,EBX			;
				mov		nScanLineEY,ECX			;
				
				//	出力ベースライン更新＆出力ライン更新
				add		EDI,lDstPitch			;
				mov		ECX,lDstPitch			;
	
				mov		lpDstBase,EDI			;
				add		lpDstLineStart,ECX		;
	
				add		lpDstLineEnd,ECX		;
	
				mov		EAX,nPutStepSX			;
				mov		EBX,nPutLineSX			;
				sub		EBX,EAX					;	//	EDI + (EBX >> 20) << 4が書き込み開始位置
				mov		nPutLineSX,EBX			;
				and		EBX,0xfff00000			;
	
				mov		EDX,nPutStepEX			;
				mov		ECX,nPutLineEX			;
				sub		ECX,EDX					;
				mov		nPutLineEX,ECX			;
				and		ECX,0xfff00000			;
	
				sub		ECX,EBX					;	//	ECXにスキャンライン長(12:20)
	
				mov		nPutLineLeng, ECX		;
	//			jc		line_skip1				;	// キャリーだと、正-負の計算に、キャリーを使用するので、
				js		line_skip1				;	// 符号を見て飛ぶようにに変更した '00.10.3.
	
				sar		ECX,20					;
	
				jz		line_skip1				;
	
				cmp		EDI,lpDstStart			;	//	出力ライン範囲チェック
				jc		line_skip1				;
	
				cmp		EDI,lpDstEnd			;
				jnc		line_skip1				;
	
				sar		EBX,20-2				;
	
				add		EDI,EBX					;	//	EDI＜－出力開始アドレス
				//	スキャンライン移動比率を求める
				cmp		ECX,1					;
				jbe		dclip_start1			;
	
				mov		EAX, nPutLineAdj		;
	
				sub		nPutLineLeng,EAX		;
				mov		EAX,nScanLineSX			;
	
				mov		EBX,nScanLineEX			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
		
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
	
				mov		nScanLineStepX,EAX		;
				
				mov		EAX,nScanLineSY			;
				mov		EBX,nScanLineEY			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
	
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
				mov		nScanLineStepY,EAX		;
	dclip_start1:								;	//	出力の右クリッピング
				lea		EBX,[EDI+ECX*4]			;	//	bx <- 出力終了アドレス
				sub		EBX,lpDstLineEnd		;
				jbe		dst_clip1				;
				sar		EBX,2					;
				sub		ECX,EBX					;
				jbe		line_skip1				;
	dst_clip1:									;
				//	スキャン開始位置取り出し	
				mov		EBX,nScanLineSX			;
				mov		EAX,nScanLineSY			;
	dst_clip2:									;	//	出力の左クリッピング
				cmp		EDI,lpDstLineStart		;
				jnc		line_loop1				;
	
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
	
				add		EDI,4					;
				dec		ECX						;
				jz		line_skip1				;
				jmp		dst_clip2				;
	line_loop1:									;
				// this loop changed by tia
				mov		nScanPointX,EBX			;
				mov		nScanPointY,EAX			;
	
				sar		EAX,20					;
				mov		ESI,lplpLineStart		;
	
				sar		EBX,20					;
	
				cmp		EBX,nSrcSX				;
				jc		ckey_skip1				;
	
				cmp		EAX,nSrcSY				;
				jc		ckey_skip1				;
				
				cmp		EBX,nSrcEX				;
				jnc		ckey_skip1				;
				
				cmp		EAX,nSrcEY				;
				jnc		ckey_skip1				;
	
				mov		ESI,[ESI+4*EAX]			;
				mov		EAX,nScanPointY			;
	
				mov		EDX,[ESI+4*EBX]			;
				mov		EBX,nScanPointX			;
	
				mov		[EDI],EDX				;
				sub		EBX,nScanLineStepX		;
	
				sub		EAX,nScanLineStepY		;
				add		EDI,4					;
	
				dec		ECX						;
				jnz		line_loop1				;
	
				jmp		line_skip1				;
	ckey_skip1:	mov		EAX,nScanPointY			;
				mov		EBX,nScanPointX			;
				//	スキャン位置移動
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
				
				add		EDI,4					;
	
				dec		ECX						;
				jnz		line_loop1				;
				jmp		line_skip1				;
	/*	使ってないby Tia
	line_skip2:	
				mov		EDX,EAX
				mov		ESI,lplpLineStart
	
				sar		EDX,20
	
				mov		ESI,[ESI+4*EDX]
				mov		EDX,EBX
	
				sar		EDX,20
	
				mov		EDX,[ESI+4*EDX]
	
				mov		[EDI],EDX
				add		EDI,4
	
				dec		ECX
				jnz		line_skip2
	*/
	line_skip1:									;
				mov		EDI,lpDstBase			;
				//	ラインカウンタデクリメント
				dec		lpPutCount[0]			;
				jnz		loop_ly1				;
	end_ly1:									;
			}
	
	
			//	ｍ成分処理
			if (lpnScanU[1]) {
				nScanStepSX = lpScanSS[1].nStepUX; //  / lpnScanU[1]
				nScanStepSY = lpScanSS[1].nStepUY; //  / lpnScanU[1]
				nScanLineSX = lpScanSS[1].nStartX;
				nScanLineSY = lpScanSS[1].nStartY;
				nPutStepSX = lpPutSS[1].nStepUX;	// / lpnScanU[1]
			}
			if (lpnScanV[1]) {
				nScanStepEX = lpScanSS[1].nStepVX; //  / lpnScanV[1]
				nScanStepEY = lpScanSS[1].nStepVY; //  / lpnScanV[1]
				nScanLineEX = lpScanSS[1].nStartX;
				nScanLineEY = lpScanSS[1].nStartY;
				nPutStepEX = lpPutSS[1].nStepVX;	// / lpnScanV[1]
			}
	
//printf("morphBltFast  3 - 3\n");
	
			asm {
				or		lpnScanU[1*4],0			;
				jz		conv_skip1				;
				//	データの固定小数変換
				mov		EAX, nScanStepSX		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[1*4]			;
				mov		nScanStepSX, EAX		;
				///////////////////////////////
				mov		EAX, nScanStepSY		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[1*4]			;
				mov		nScanStepSY, EAX		;
				//////////////////////////////
				sal		nScanLineSX,20			;
				sal		nScanLineSY,20			;
				/////////////////////////////
				mov		EAX,nPutStepSX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[1*4]			;
				mov		nPutStepSX,EAX			;
	conv_skip1:									;
				or		lpnScanV[1*4],0			;
				jz		conv_skip2				;
				///////////////////////////////
				mov		EAX,nScanStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[1*4]			;
				mov		nScanStepEX, EAX		;
				///////////////////////////////
				mov		EAX,nScanStepEY			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[1*4]			;
				mov		nScanStepEY,EAX			;
				//////////////////////////////
				sal		nScanLineEX,20			;
				sal		nScanLineEY,20			;
				////////////////////////////
				mov		EAX,nPutStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[1*4]			;
				mov		nPutStepEX,EAX			;
	conv_skip2:									;
				or		lpPutCount[1*4],0		;
				jz		end_ly2					;
				//	ｙ方向ループ
	loop_ly2:									;
				//	スキャン開始終了位置更新
				mov		EAX,nScanStepSX			;
				mov		EBX,nScanLineSX			;
	
				mov		EDX,nScanStepSY			;
				sub		EBX,EAX					;
	
				mov		ECX,nScanLineSY			;
				mov		nScanLineSX,EBX			;
	
				sub		ECX,EDX					;
				mov		EAX,nScanStepEX			;
				
				mov		nScanLineSY,ECX			;
				mov		EBX,nScanLineEX			;
				
				sub		EBX,EAX					;
				mov		ECX,nScanLineEY			;
				
				mov		EDX,nScanStepEY			;
				sub		ECX,EDX					;
				
				mov		nScanLineEX,EBX			;
				mov		nScanLineEY,ECX			;
				
				//	出力ベースライン更新＆出力ライン更新
				add		EDI,lDstPitch			;
				mov		ECX,lDstPitch			;
	
				mov		lpDstBase,EDI			;
				add		lpDstLineStart,ECX		;
	
				mov		EAX,nPutStepSX			;
				mov		EBX,nPutLineSX			;
	
				sub		EBX,EAX					;	//	EDI + (EBX >> 20) << 4が書き込み開始位置
				add		lpDstLineEnd,ECX		;
	
				mov		EDX,nPutStepEX			;
				mov		ECX,nPutLineEX			;
	
				mov		nPutLineSX,EBX			;
				sub		ECX,EDX					;
	
				and		EBX,0xfff00000			;
				mov		nPutLineEX,ECX			;
	
				and		ECX,0xfff00000			;
	
				sub		ECX,EBX					;		//	ECXにスキャンライン長(12:20)
	
				mov		nPutLineLeng, ECX		;
	//			jc		line_skip3				;
				js		line_skip3				;	// 符号を見て飛ぶようにに変更した '00.10.3.
	
				sar		ECX,20					;
	
				jz		line_skip3				;
	
				cmp		EDI,lpDstStart			;	//	出力ライン範囲チェック
				jc		line_skip3				;
	
				cmp		EDI,lpDstEnd			;
				jnc		line_skip3				;
	
				sar		EBX,20-2				;
	
				add		EDI,EBX					;	//	EDI＜－出力開始アドレス
				//	スキャンライン移動比率を求める
				cmp		ECX,1					;
				jbe		dclip_start2			;
	
				mov		EAX, nPutLineAdj		;
	
				sub		nPutLineLeng,EAX		;
				mov		EAX,nScanLineSX			;
	
				mov		EBX,nScanLineEX			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
		
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
	
				mov		nScanLineStepX,EAX		;
				
				mov		EAX,nScanLineSY			;
				mov		EBX,nScanLineEY			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
	
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
				mov		nScanLineStepY,EAX		;
	dclip_start2:								;	//	出力の右クリッピング
				lea		EBX,[EDI+ECX*4]			;	//	bx <- 出力終了アドレス
				sub		EBX,lpDstLineEnd		;
				jbe		dst_clip3				;
				sar		EBX,2					;
				sub		ECX,EBX					;
				jbe		line_skip3				;
	dst_clip3:		;
				//	スキャン開始位置取り出し	
				mov		EBX,nScanLineSX			;
				mov		EAX,nScanLineSY			;
	dst_clip4:									;	//	出力の左クリッピング
				cmp		EDI,lpDstLineStart		;
				jnc		line_loop2				;
	
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
	
				add		EDI,4					;
				dec		ECX						;
				jz		line_skip3				;
				jmp		dst_clip4				;
	line_loop2:									;
				mov		nScanPointX,EBX			;
				mov		nScanPointY,EAX			;
	
				sar		EAX,20					;
				mov		ESI,lplpLineStart		;
	
				sar		EBX,20					;
	
				cmp		EBX,nSrcSX				;
				jc		line_skip4				;
	
				cmp		EAX,nSrcSY				;
				jc		line_skip4				;
				
				cmp		EBX,nSrcEX				;
				jnc		line_skip4				;
				
				cmp		EAX,nSrcEY				;
				jnc		line_skip4				;
				
				mov		ESI,[ESI+4*EAX]			;
				mov		EAX,nScanPointY			;
	
				mov		EDX,[ESI+4*EBX]			;
				mov		EBX,nScanPointX			;
	
				mov		[EDI],EDX				;
				sub		EBX,nScanLineStepX		;
	
				sub		EAX,nScanLineStepY		;
				add		EDI,4					;
	
				dec		ECX						;
				jnz		line_loop2				;
	
				jmp		line_skip3				;
	line_skip4:	mov		EAX,nScanPointY			;
				mov		EBX,nScanPointX			;
				//	スキャン位置移動
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
				//	出力位置移動
				add		EDI,4					;
				dec		ECX						;
				jnz		line_loop2				;
	line_skip3:									;
				mov		EDI,lpDstBase			;
				//	ラインカウンタデクリメント
				dec		lpPutCount[1 * 4]		;
				jnz		loop_ly2				;
	end_ly2:									;
			}
	
//printf("morphBltFast  3 - 4\n");
			
			//	ｍ成分処理
		if (lpPutCount[2]) {
			if (lpnScanU[2]) {
				nScanStepSX = lpScanSS[2].nStepUX; //  / lpnScanU[2]
				nScanStepSY = lpScanSS[2].nStepUY; //  / lpnScanU[2]
				nScanLineSX = lpScanSS[2].nStartX;
				nScanLineSY = lpScanSS[2].nStartY;
				nPutStepSX = lpPutSS[2].nStepUX;	// / lpnScanU[2]
			}
			if (lpnScanV[2]) {
				nScanStepEX = lpScanSS[2].nStepVX; //  / lpnScanV[2]
				nScanStepEY = lpScanSS[2].nStepVY; //  / lpnScanV[2]
				nScanLineEX = lpScanSS[2].nStartX;
				nScanLineEY = lpScanSS[2].nStartY;
				nPutStepEX = lpPutSS[2].nStepVX;	// / lpnScanV[2]
			}
			asm {
				or		lpnScanU[2*4],0			;
				jz		conv_skip3				;
				//	データの固定小数変換
				mov		EAX, nScanStepSX		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[2*4]			;
				mov		nScanStepSX, EAX		;
				///////////////////////////////
				mov		EAX, nScanStepSY		;
				mov		EDX, EAX				;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[2*4]			;
				mov		nScanStepSY, EAX		;
				//////////////////////////////
				sal		nScanLineSX,20			;
				sal		nScanLineSY,20			;
				/////////////////////////////
				mov		EAX,nPutStepSX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanU[2*4]			;
				mov		nPutStepSX,EAX			;
	conv_skip3:		;
				or		lpnScanV[2*4],0			;
				jz		conv_skip4				;
				///////////////////////////////
				mov		EAX,nScanStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[2*4]			;
				mov		nScanStepEX, EAX		;
				///////////////////////////////
				mov		EAX,nScanStepEY			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[2*4]			;
				mov		nScanStepEY,EAX			;
				//////////////////////////////
				sal		nScanLineEX,20			;
				sal		nScanLineEY,20			;
				////////////////////////////
				mov		EAX,nPutStepEX			;
				mov		EDX,EAX					;
				sar		EDX,31					;
				sal		EAX,20					;
				idiv	lpnScanV[2*4]			;
				mov		nPutStepEX,EAX			;
	conv_skip4:									;
				//	ｙ方向ループ
	loop_ly3:									;
				//	スキャン開始終了位置更新
				mov		EAX,nScanStepSX			;
				mov		EBX,nScanLineSX			;
	
				mov		EDX,nScanStepSY			;
				sub		EBX,EAX					;
	
				mov		ECX,nScanLineSY			;
				mov		nScanLineSX,EBX			;
	
				sub		ECX,EDX					;
				mov		EAX,nScanStepEX			;
				
				mov		nScanLineSY,ECX			;
				mov		EBX,nScanLineEX			;
				
				sub		EBX,EAX					;
				mov		ECX,nScanLineEY			;
				
				mov		EDX,nScanStepEY			;
				sub		ECX,EDX					;
				
				mov		nScanLineEX,EBX			;
				mov		nScanLineEY,ECX			;
				
				//	出力ベースライン更新＆出力ライン更新
				add		EDI,lDstPitch			;
				mov		ECX,lDstPitch			;
	
				mov		lpDstBase,EDI			;
				add		lpDstLineStart,ECX		;
	
				mov		EAX,nPutStepSX			;
				mov		EBX,nPutLineSX			;
	
				sub		EBX,EAX					;	//	EDI + (EBX >> 20) << 4が書き込み開始位置
				add		lpDstLineEnd,ECX		;
	
				mov		EDX,nPutStepEX			;
				mov		ECX,nPutLineEX			;
	
				mov		nPutLineSX,EBX			;
				sub		ECX,EDX					;
	
				and		EBX,0xfff00000			;
				mov		nPutLineEX,ECX			;
	
				and		ECX,0xfff00000			;
	
				sub		ECX,EBX					;	//	ECXにスキャンライン長(12:20)
	
				mov		nPutLineLeng, ECX		;
	//			jc		line_skip5				;
				js		line_skip5				;	// 符号を見て飛ぶようにに変更した '00.10.3.
	
				sar		ECX,20					;
	
				jz		line_skip5				;
	
				cmp		EDI,lpDstStart			;	//	出力ライン範囲チェック
				jc		line_skip5				;
	
				cmp		EDI,lpDstEnd			;
				jnc		line_skip5				;
	
				sar		EBX,20-2				;
	
				add		EDI,EBX					;		//	EDI＜－出力開始アドレス
				//	スキャンライン移動比率を求める
				cmp		ECX,1					;
				jbe		dclip_start3			;
	
				mov		EAX, nPutLineAdj		;
	
				sub		nPutLineLeng,EAX		;
				mov		EAX,nScanLineSX			;
	
				mov		EBX,nScanLineEX			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
		
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
	
				mov		nScanLineStepX,EAX		;
				
				mov		EAX,nScanLineSY			;
				mov		EBX,nScanLineEY			;
	
				sub		EAX,EBX					;
	
				mov		EDX,EAX					;
	
				sal		EAX,20					;
	
				sar		EDX,12					;
	
				idiv	nPutLineLeng			;
				mov		nScanLineStepY,EAX		;
	dclip_start3:								;				//	出力の右クリッピング
				lea		EBX,[EDI+ECX*4]			;				//	bx <- 出力終了アドレス
				sub		EBX,lpDstLineEnd		;
				jbe		dst_clip5				;
				sar		EBX,2					;
				sub		ECX,EBX					;
				jbe		line_skip5				;
	dst_clip5:									;
				//	スキャン開始位置取り出し	
				mov		EBX,nScanLineSX			;
				mov		EAX,nScanLineSY			;
	dst_clip6:									;	//	出力の左クリッピング
				cmp		EDI,lpDstLineStart		;
				jnc		line_loop3				;
	
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
	
				add		EDI,4					;
				dec		ECX						;
				jz		line_skip5				;
				jmp		dst_clip6				;
	line_loop3:									;
				mov		nScanPointX,EBX			;
				mov		nScanPointY,EAX			;
	
				sar		EAX,20					;
				mov		ESI,lplpLineStart		;
	
				sar		EBX,20					;
	
				cmp		EBX,nSrcSX				;
				jc		line_skip6				;
	
				cmp		EAX,nSrcSY				;
				jc		line_skip6				;
				
				cmp		EBX,nSrcEX				;
				jnc		line_skip6				;
				
				cmp		EAX,nSrcEY				;
				jnc		line_skip6				;
				
				mov		ESI,[ESI+4*EAX]			;
				mov		EAX,nScanPointY			;
	
				mov		EDX,[ESI+4*EBX]			;
				mov		EBX,nScanPointX			;
	
				mov		[EDI],EDX				;
				sub		EBX,nScanLineStepX		;
	
				sub		EAX,nScanLineStepY		;
				add		EDI,4					;
	
				dec		ECX						;
				jnz		line_loop3				;
	
				jmp		line_skip5				;
	line_skip6:	mov		EAX,nScanPointY			;
				mov		EBX,nScanPointX			;
				//	スキャン位置移動
				sub		EBX,nScanLineStepX		;
				sub		EAX,nScanLineStepY		;
				//	出力位置移動
				add		EDI,4					;
				dec		ECX						;
				jnz		line_loop3				;
	line_skip5:		;
				mov		EDI,lpDstBase			;
				//	ラインカウンタデクリメント
				dec		lpPutCount[2 * 4]		;
				jnz		loop_ly3;				;
			}
		}
//printf("morphBltFast  --END--\n");
		
		return 0;
	}

	/// DIB32 の互換属性設定
	void setDIB32Compatible() {
		m_lpdwSrc = cast(uint*) surface.pixels;
		m_lPitch = surface.w * 4;
		
		m_lpdwLineStart = null;
		for (int i = 0; i < surface.h; ++i) {
			m_lpdwLineStart ~= cast(uint*) ( cast(ubyte*)m_lpdwSrc + m_lPitch * i);
		}
		
		m_rcRect.setRect(0, 0, surface.w, surface.h);
		printf("compatible surface\n");
	}

	/**
		yaneSDK2nd の DIB32と互換性持たせるために、用意する。まんどいなー
	*/	
	uint*	m_lpdwSrc;			//	確保したものをQWORDでアラインしたもの
	RectInt	m_rcRect;			//	DIBのサイズは(m_rcRect.right,m_rcRect.bottom)
	uint*[]	m_lpdwLineStart;	//	各ラインの先頭アドレステーブル
	long	m_lPitch;			//	１ラインのバイト数(通例m_nSizeX*4)

protected:
	SDL_Surface* surface;	//	サーフェースの実体
	Surface tmpSurface;

	void createLineAdr() {
		ubyte* lpData = cast(ubyte*) surface.pixels;
		if ( checkRGBA8888() ) {
			for ( int i = 0; i < surface.h; ++i) {
				m_lpdwLineStart ~= cast(uint*) &lpData[ surface.w * 32 * i ]; 
			}
		} else {
			for ( int i = 0; i < surface.h; ++i) {
				m_lpdwLineStart ~= cast(uint*) &lpData[ surface.w * 24 * i ]; 
			}
		}
printf("Line Adr create!\n");
	}
	
	
private:

	//	スキャン及び出力用の開始点（Ｓｘ，Ｓｙ）とＵＶステップ量（Ｐｘ，Ｐｙ）構造体
	//	アセンブラでの場合ここに最初U,Vの終点座標差をＣ言語側で求めて
	//	かいておく。そして割り算やって格納
	struct StartAndStep	{
		int		nStartX;
		int		nStartY;
		int		nStepUX;
		int		nStepUY;
		int		nStepVX;
		int		nStepVY;
	};
	//	４点のポイントアクセス用列挙体
	enum Point { A, B, C, D, POINT_NUM };
	//	出力先のソート用構造体
	struct	DstSort {
		Point	p;
		int		x;
		int		y;
	};
	
	extern (C) {
		/// qsort用比較関数
		static int pointsort(const void* element1, const void* element2)
		{
			int		iRes;
			iRes = ( cast(DstSort*) (element1)).y - ( cast(DstSort*) (element2)).y;
			if (iRes == 0) {
				return ( cast(DstSort*) (element1)).x - ( cast(DstSort*) (element2)).x;
			} else {
				return iRes;
			}
		}
	}

	
}
