// AlphaBitmap3 for Delphi 6- ,C++Builder 6-
// Copyright(C)'2000- buin2gou(buin2gou2@ybb.ne.jp)
//
// 
// このライブラリは、TBitmapをラッピング（継承）して半透明処理機能などを追加したものです。
// 非常に高速な半透明処理機能を簡単にご使用出来ます。
// 
// 参考・勝手に引用ホームページ
//
// http://www.ngy.1st.ne.jp/~kengo/
// スキャンラインの参考：http://www2s.biglobe.ne.jp/~aks-lab/
// スムースフォントの参考：http://hp.vector.co.jp/authors/VA012950/aa/
// http://homepage1.nifty.com/beny/
// MMX対応の参考：http://www.fides.dti.ne.jp/~tokai/vc/
// MMX参考：http://www.moon.sannet.ne.jp/heppoko/index.html
// 
// 転載・改変はご自由にどうぞ。
// 



unit ABitmaplight;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, types;

  type
  PDWordArray = ^TDWordArray;
  TDWordArray = array[0..8191] of DWord;

  TRGBA=packed record
       r:Byte;
       g:Byte;
       b:Byte;
       a:Byte;
  end;
  TRGBAArray = array[0..8191] of TRGBA;
  PRGBAArray = ^TRGBAArray;


//クラス外の自由に使える関数

//MMX・SSE使用チェック
//function MMXCheck:Boolean;

procedure EffectResizeMMX(Var inBMP:TBitmap;width,height:Integer);
function SuperTextOut(ToBMP:TBitmap;X,Y:Integer;bFont:TFont;Msg:String):TPoint;


//bit処理
function  getbit(i,cnt:byte):byte;
function  setbit(i,cnt,inbit:byte):byte;
//丸め込み
function RoundByte(data:Integer):Byte;
//サイズ調整関数
function SetXYWHAuto(var ix,iy,iw,ih,ox,oy,ow,oh:Integer):Boolean;
//３２ビットアルファ付き画像を生成。RGBA形式。ARGBじゃないよ。
//procedure Convert24Ato32(BMP24,ABMP,out32BMP:TBitmap);
//トランジション用画像変換関数

//サイズチェッカー。
function SelfCheck(BMP:TBitmap):Boolean;


type
  TABitmap = class(TBitmap)
  private
    { Private 宣言 }

  protected
    { Protected 宣言 }
  public
    { Public 宣言 }

    //生成・開放
    constructor Create; override;
    destructor  Destroy; override;

    //オーバーライドしてフルカラー化
    procedure LoadFromFile(const FileName:String);override;
    procedure LoadFromStream(Stream:TStream);override;
    procedure Assign(Source:TPersistent);override;

    //３２ビット変換
    procedure Do32;

    procedure GetRGB(x,y:Integer;var r,g,b:Byte);

    //点を描画(スキャンラインを全て使用)
  //  procedure GetColor(x,y:Integer;var col:TColor);
    procedure GetRGBColor(x,y:Integer;var col:TColor);

    //全部指定色にフィルする。
   // procedure FillBMP(const pxlRGB:TColor);


    //αブレンド関連---------------------------------------------------
    //ノーマル処理
    procedure ColorAlphaMMX(x,y,w,h,ax,ay:Integer;BMP:TBitmap;iA:WORD);

    //カラーキー処理
   // procedure ColorKey(x,y,w,h,ax,ay:Integer;BMP:TBitmap;Col:TColor);
    procedure ColorKeyAlphaMMX(x,y,w,h,ax,ay:Integer;BMP:TBitmap;Col:TColor;iA:WORD);

 //   procedure DrawEx(Dest:TRect;bitmap:TBitmap;mode:shortInt);
 //   procedure DrawLogic(Dest:TRect;Graphic:TGraphic;mode:shortInt=0);

  published
    { Published 宣言 }
  end;


implementation

Function RoundByte(data:Integer):Byte;
begin
  if Data>255 then Data:=255
  else if Data< 0 then Data:=0;
  Result:=Data;
end;



function SetOutXYWHSuper(var ix,iy,iw,ih:Double;var ox,oy:Double;var ow,oh:Integer;iWW,iHH,oWW,oHH:Integer):Boolean;
var iZW,iZH:Double;
begin

   iZW:=iw/ow;
   iZH:=ih/oh;


   Result:=False;

   //入力位置が変なモノも終了。
   if (ix<0) or (ix>iWW) then exit;
   if (iy<0) or (iy>iHH) then exit;

   //出力位置は適切か調べる。
   If oX>=oWW then exit;
   If oY>=oHH then exit;
   If oX+oW<=0 then exit;
   If oY+oH<=0 then exit;


   {表示エリアに入るサイズで、マイナスな場合}
   //マイナスの場合の変更処理
   If oX<0 then begin
      //入力サイズの変更
      iw:=iZW*(oW+oX);
      iX:=iX+Abs(oX)*iZW;

      oW:=Trunc(oW+oX);
      oX:=0;

   end;

   If oY<0 then begin
      //入力サイズの変更
      ih:=iZH*oh;
      iy:=iY+(Abs(oY)*iZH);

      oH:=Trunc(oH+oY);
      oY:=0;
   end;

   {表示エリアを越えているだけの場合}
   //範囲越えの時の変更処理。
   If oX+oW>oWW then begin
      //入力位置も変更しておく。
      iW:=iZW*(oWW-oX);

      //幅をX方向を引いて代入。
      oW:=Trunc(oWW-oX);
   end;

   If oY+oH>oHH then begin
      //入力位置も変更しておく。
      iH:=iZH*(oHH-oY);

      //幅をX方向を引いて代入。
      oH:=Trunc(oHH-oY);
   end;


   //編集結果のチェック。
   if ow<=0 then exit;
   if oh<=0 then exit;
   if (ix<0) or (ix>iww) then exit;
   if (iy<0) or (iy>ihh) then exit;
   if (ix+iw)>iWW then iw:=iWW-iX;
   if (iy+ih)>iHH then ih:=iHH-iY;

   //ShowMessage(Format('%d,%d %d,%d',[iw,ih,ow,oh]));

   //結果オッケー。
   Result:=True;

end;



constructor TABitmap.Create;
begin
  Inherited Create;

  PixelFormat:=pf32Bit;

end;

destructor TABitmap.Destroy;
begin

  Inherited Destroy;
end;



procedure TABitmap.Do32;
begin
   Self.PixelFormat:=pf32Bit;
end;


procedure TABitmap.LoadFromFile(const FileName:String);
begin
  Inherited LoadFromFile(FileName);

  Do32;

end;

procedure TABitmap.LoadFromStream(Stream:TStream);
begin
  inherited LoadFromStream(Stream);

  Do32;
end;

procedure TAbitmap.Assign(Source:TPersistent);
begin
  Inherited Assign(Source);

  Do32;

end;

procedure TABitmap.GetRGB(x,y:Integer;var r,g,b:Byte);
var i   :Integer;
    pBit:PByteArray;
begin


    //スキャンライン取得
    pBit:=ScanLine[y];

    i:=x*4;
    b:=pBit[i];
    g:=pBit[i+1];
    r:=pBit[i+2];

end;

  {
procedure TABitmap.GetColor(x,y:Integer;var col:TColor);
var r,g,b:Byte;
begin

  GetRGB(x,y,r,g,b);
  col:=RGB(r,g,b);

end;
  }
procedure TABitmap.GetRGBColor(x,y:Integer;var col:TColor);
var r,g,b:Byte;
begin

  GetRGB(x,y,r,g,b);
  col:=RGB(b,g,r);

end;

//------------------------------------
//
// 細かい命令。
//
//------------------------------------

{
procedure TABitmap.FillBMP(const pxlRGB:TColor);
var pBit:PByteArray;
    ew,y:Integer;
begin

 //出力先がないときも終了
 If not SelfCheck(Self) then exit;


 ew:=(Self.Width);

   for y:=0 to Self.Height-1 do begin
     pBit:= Self.ScanLine[y];
     asm
       push esi; push edi; push ebx; // レジスタ退避
       mov esi,pBit;
       mov ebx,pxlRGB;
       mov ecx,ew;
      @loop:
         mov [esi],ebx;
         add esi,4;
         dec ecx;
         jnz @loop;

       pop ebx; pop edi; pop esi;    // レジスタ復活
     end;
   end;
end;

 }


//------------------------------------
//
// 半透明処理プログラム
//
//------------------------------------

       {
procedure TABitmap.ColorKey(x,y,w,h,ax,ay:Integer;BMP:TBitmap;Col:TColor);
var
  pBit,pBit2: PByteArray;
  pxlRGB    : LongInt;
  e,ew,k,k2,ix,iy,iw,ih,ox,oy,ow,oh:Integer;
begin

   If not SelfCheck(Self) then exit;
   //出力先がないときも終了
   If not SelfCheck(BMP) then exit;


   //透過色
   pxlRGB:=ColorToRGB(Col);
   //pxlRGB:=Col;
   //サイズの調整
   ix:=ax;
   iy:=ay;
   iw:=w;
   ih:=h;
   ox:=x;
   oy:=y;
   ow:=BMP.Width;
   oh:=BMP.Height;

   If not SetXYWHAuto(ix,iy,iw,ih,ox,oy,ow,oh) then exit;

   k:=ox*4;//出力先位置
   k2:=ix*4;//入力先位置
   ew:=iw;



   for e:=0 to ih-1 do begin
     pBit:= ScanLine[e+iy];
     pBit2:= BMP.ScanLine[e+oy];
     asm
       push esi; push edi; push ebx; // レジスタ退避
       mov esi,pBit;
       mov edi,pBit2;
       add edi,k;
       add esi,k2;
       mov ebx,pxlRGB;
       and ebx,$00FFFFFF;
       mov ecx,ew;
      @loop_horz:
         mov eax,[esi];
         and eax,$00FFFFFF;
         cmp eax,ebx;
         je  @put_pixel_end;
         //コピー。
         mov [edi],eax;

         @put_pixel_end:
         add edi,4;
         add esi,4;
         dec ecx;
         jnz @loop_horz;

       pop ebx; pop edi; pop esi;    // レジスタ復活
     end;
   end;

end;
        }

procedure TABitmap.ColorAlphaMMX(x,y,w,h,ax,ay:Integer;BMP:TBitmap;iA:WORD);
var dwAlpha,dwAlpha2:DWORD;
    dwAlpha64,dwAlpha264:array[0..1] of DWORD;
    lpSrc1,lpSrc2:PByteArray;
    e,ew,k,k2,ix,iy,iw,ih,ox,oy,ow,oh:Integer;
begin
  
   //画像が無いときのエラー防止用。
  // If not SelfCheck(Self) then exit;
   //出力先がないときも終了
  // If not SelfCheck(BMP) then exit;
   
   ix:=ax;
   iy:=ay;
   iw:=w;
   ih:=h;
   ox:=x;
   oy:=y;
   ow:=BMP.Width;
   oh:=BMP.Height;

   If not SetXYWHAuto(ix,iy,iw,ih,ox,oy,ow,oh) then
   begin
       exit;
   end;
//windows.MessageBox(0,PChar(IntToStr(self.Height)),PChar(IntToStr(self.Width)),MB_OK);

   k:=ox*4;//出力先位置
   k2:=ix*4;//入力先位置
   ew:=iw;

   dwAlpha:=iA;
   dwAlpha2:=256-iA;

   //外に出しておいて高速化。
   asm
     movd mm4,dwAlpha;
     punpcklwd mm4,mm4;
     punpckldq mm4,mm4; // mm4 =  0α0α0α0α
     movq dwAlpha64,mm4;

     movd mm5,dwAlpha2;
     punpcklwd mm5,mm5;
     punpckldq mm5,mm5; // mm5 = 0(1-α)0(1-α)0(1-α)0(1-α)
     movq dwAlpha264,mm5;

     emms;
   end;



   for e:=0 to ih-1 do begin
      lpSrc1:=Self.ScanLine[e+iy];
      lpSrc2:=BMP.ScanLine[e+oy];

      asm
        push eax;push ecx;push edx; // レジスタ退避
        mov eax,ew;  // eax = カウンタ
        mov ecx,lpSrc1;  // ecx = コピー元1　アドレス
        mov edx,lpSrc2;  // edx = コピー元・先　アドレス

        //進めておく
        add edx,k;
        add ecx,k2

        movq mm4,dwAlpha64;
        movq mm5,dwAlpha264;
        pxor mm6,mm6; // mm6 = パック用ダミー = 0
        pxor mm7,mm7; // mm7 = パック用ダミー = 0

      @LOOP1:
        // データ読み込み(32 bit)
	movd mm0,[ecx];
	movd mm1,[edx];

	// byte -> word にアンパック
	punpcklbw mm0,mm6;
	punpcklbw mm1,mm7;


	// パック掛け算
	pmullw mm0,mm4;
	pmullw mm1,mm5;

	//  word 単位で足して256で割る
	paddw mm0,mm1;
	psrlw mm0,8;


	// word->byte にパックして転送
	packuswb mm0,mm6;
	movd [edx],mm0;

	// カウンタアップ
	add ecx,4;
	add edx,4;

	dec eax;
	jne @LOOP1;
	emms;
        pop edx;pop ecx;pop eax;    // レジスタ復活
      end;
  end;

end;

procedure TABitmap.ColorKeyAlphaMMX(x,y,w,h,ax,ay:Integer;BMP:TBitmap;Col:TColor;iA:WORD);
var dwAlpha,dwAlpha2:DWORD;
    dwAlpha64,dwAlpha264:array[0..1] of DWORD;
    lpSrc1,lpSrc2:PByteArray;
    e,ew,k,k2,ix,iy,iw,ih,ox,oy,ow,oh:Integer;
    pxlRGB    :LongInt;
begin


   //画像が無いときのエラー防止用。
   If not SelfCheck(Self) then exit;
   //出力先がないときも終了
   If not SelfCheck(BMP) then exit;


   ix:=ax;
   iy:=ay;
   iw:=w;
   ih:=h;
   ox:=x;
   oy:=y;
   ow:=BMP.Width;
   oh:=BMP.Height;

   If not SetXYWHAuto(ix,iy,iw,ih,ox,oy,ow,oh) then exit;

   k:=ox*4;//出力先位置
   k2:=ix*4;//入力先位置
   ew:=iw;

   dwAlpha:=iA;
   dwAlpha2:=256-iA;

   //外に出しておいて高速化。
   asm
     movd mm4,dwAlpha;
     punpcklwd mm4,mm4;
     punpckldq mm4,mm4; // mm4 =  0α0α0α0α
     movq dwAlpha64,mm4;

     movd mm5,dwAlpha2;
     punpcklwd mm5,mm5;
     punpckldq mm5,mm5; // mm5 = 0(1-α)0(1-α)0(1-α)0(1-α)
     movq dwAlpha264,mm5;

     emms;
   end;

   pxlRGB:=ColorToRGB(Col);

   for e:=0 to ih-1 do begin
      lpSrc1:=Self.ScanLine[e+iy];
      lpSrc2:=BMP.ScanLine[e+oy];

      asm
        push eax;push ebx;push ecx;push edx;push esi; // レジスタ退避
        mov eax,ew;  // eax = カウンタ
        mov ecx,lpSrc1;  // ecx = コピー元1　アドレス
        mov edx,lpSrc2;  // edx = コピー元・先　アドレス

        mov ebx,pxlRGB;
        and ebx,$00FFFFFF;

        //進めておく
        add edx,k;
        add ecx,k2

        movq mm4,dwAlpha64;
        movq mm5,dwAlpha264;
        pxor mm6,mm6; // mm6 = パック用ダミー = 0
        pxor mm7,mm7; // mm7 = パック用ダミー = 0

      @LOOP1:

	mov esi,[ecx];
        and esi,$00FFFFFF;
        cmp esi,ebx;
        je @next;

        // データ読み込み(32 bit)
	movd mm0,[ecx];
	movd mm1,[edx];

	// byte -> word にアンパック
	punpcklbw mm0,mm6;
	punpcklbw mm1,mm7;

	// パック掛け算
	pmullw mm0,mm4;
	pmullw mm1,mm5;

	//  word 単位で足して256で割る
	paddw mm0,mm1;
	psrlw mm0,8;


	// word->byte にパックして転送
	packuswb mm0,mm6;
	movd [edx],mm0;

        @next:

	// カウンタアップ
	add ecx,4;
	add edx,4;

	dec eax;
	jne @LOOP1;
	emms;
        pop esi;pop edx;pop ecx;pop ebx;pop eax;    // レジスタ復活
      end;
  end;

end;



//////////////////////////////////////////////////////////
//
//
// Abitmapクラス外関数
//
//
//////////////////////////////////////////////////////////



function getbit(i,cnt:byte):byte;
begin
    i := i shl cnt;
    i := i shr 7;
    result := i;
end;

function setbit(i,cnt,inbit:byte):byte;
begin
    inbit:=inbit shl (7-cnt);
    i := i or inbit;
    result:=i;
end;


function SetXYWHAuto(var ix,iy,iw,ih,ox,oy,ow,oh:Integer):Boolean;
begin

  //そもそも、範囲オーバーな位置を検出
  Result:=False;
  If (ox<0)  and (ox+iw<=0) then exit;
  If (oy<0)  and (oy+ih<=0) then exit;
  If (ox>=ow) then exit;
  If (oy>=oh) then exit;

  Result:=True;
  {X関係}
  If ox<0 then begin
     //iX<0
     iw:=iw-Abs(ox);
     ix:=ix+Abs(ox);
     ox:=0;
  end else If (0<=ox+iw) and (ox+iw<=ow) then begin
     //0<iX+iW<oW
     //ix:=0;
     //特に何も無し

  end else begin
     //ow>ix+iw
     iw:=ow-Abs(ox);
     //ix:=0;
  end;

  {Y関係}
  If oy<0 then begin
     //iX<0
     ih:=ih-Abs(oy);
     iy:=iy+Abs(oy);
     oy:=0;
  end else If (0<=oy+ih) and (oy+ih<=oh) then begin
     //0<iX+iW<oW
     //iy:=0;
     //特に何も無し

  end else begin
     //oh>oy+ih
     ih:=oh-Abs(oy);
     //iy:=0;
  end;




end;

function SelfCheck(BMP:TBitmap):Boolean;
begin
  Result:=True;
  If BMP.Width<=0 then Result:=False;

end;

procedure EffectResizeMMX(var inBMP:TBitmap;width,height:Integer);
var pBit,pBitN,pBit2:PDWORDArray;
    y,x:Integer;//ループ用
    zx,zy:Integer;//入力もとの位置
    mzoomx,mzoomy,zoomx,zoomy:DWORD;//ズーム倍率。

    //高速化用。
    i:Integer;//Xの代用。
    k:Integer;//ZXの一定移動幅の計算。
    //高速化用その２.
    l:DWORD;//Yの位置の次への値の比率。

    ix8:Integer;
    //端の考慮用
    tw,th:Integer;

    //高速化用・バイリニアの割合。
    l2,l3:DWORD;
    ix,iy,iw,ih,ox,oy,ow,oh:Integer;
    ix3,iy3,ox3,oy3,iw3,ih3:Double;

    //MMX用
    ew,ew2:Integer;
    iMM4:DWORD;
    ix8_2:Integer;
    ox4,ix4:Integer;

    outBMP:TBitmap;

begin

  ix3:=0; iy3:=0; iw3:=inBMP.width; ih3:=inBMP.height;
  ox3:=0; oy3:=0; ow :=width; oh :=height;


  inBMP.PixelFormat:=pf32bit;
  outBMP:=TBitmap.Create();
  outBMP.PixelFormat:=pf32bit;
  outBMP.Width:=width;
  outBMP.Height:=height;

  //逆数のズーム倍率を求める（ズーム先を基準にしているため)
  mzoomx:=Trunc(iw3*$FFFF / ow);//割るときは全部シフトで代用できるようにする。
  mzoomy:=Trunc(ih3*$FFFF / oh);

  //通常のズーム倍率を取得
  zoomx :=Trunc(ow*$FFFF / iw3);//割るときは全部シフトで代用できるようにする。
  zoomy :=Trunc(oh*$FFFF / ih3);

  //範囲内かどうかをチェックする。
  If not SetoutXYWHSuper(ix3,iy3,iw3,ih3,ox3,oy3,ow,oh,InBMP.Width,InBMP.Height,OutBMP.Width,OutBMP.Height) then exit;

  //Y位置のループ高速化用。
  l:=0;

  ix8:=Trunc(ix3*($FFFF));
  //ix8:=Trunc(ix3) shl 16;

  ix:=Trunc(ix3);
  iy:=Trunc(iy3);
  ox:=Trunc(ox3);
  oy:=Trunc(oy3);
  iw:=Trunc(iw3);
  ih:=Trunc(ih3);

  //端を考慮。(端を抜いた理論的処理サイズを決定。)
  tw:=(iw-1)*zoomx shr 16;
  if InBMP.Height>iy+ih then begin
     th:=oh;
  end else begin
     th:=(ih-1)*zoomy div $FFFF;
  end;

  zy:=-1;

  //MMX用
  iMM4:=$00FF00FF;
  //幅。
  ew:=tw;
  ew2:=ow-tw;

  ox4:=ox shl 2;

  //ix8_2:=(iw-2) shl 8;

  for y:=oy to oy+th-1 do begin
      pBit2:=OutBMP.ScanLine[y];


      ///現在の入力画像の高さ位置を計算
      if zy<>iy+(l shr 16) then begin
         zy:=iy+(l shr 16);

         pBit :=InBMP.ScanLine[zy];
         pBitN:=InBMP.ScanLine[zy+1];
      end;
      //バイリニアの割合（Y方向）
      l3:=(l-((l shr 16) shl 16)) shr 8;//py


      asm
        push eax;push ebx;push ecx;push edx;push edi;push esi; // レジスタ退避

        //ピクセル位置
        mov edi,pBit;//Src
        mov esi,pBitN;//Src+1
        mov ebx,pBit2;//Dest

        //カウンター。
        mov eax,ew;

        //出力位置を調整。
        add ebx,ox4;


        //あまっているのは、ecx,edx
        mov ecx,ix8;//位置の絶対位置情報と値の保持

        //初期化
        pxor mm6,mm6;
        movd mm7,iMM4;//mm7には、$00FF00FFが入る。
        punpckldq mm7,mm7;//$00FF00FF 00FF00FFとコピーする。dword>qword

        //まずは、通常のループです。
        @LOOP1:
         //取得位置を指定。

            //元画像の位置を計算。
            mov edx,ecx;
            shr edx,16;

            //元画像のポインタを移動
            //元画像の入力(64ビット入力。)
            movq mm2,qword ptr[edi+edx*4];
            movq mm3,qword ptr[esi+edx*4];
            movq mm0,mm2;
            movq mm1,mm3;

            //元画像を整頓
            psrlq mm2,32;
            psrlq mm3,32;

            //QWORDに広げて計算できるようにする。
            punpcklbw mm0,mm6;// a
            punpcklbw mm1,mm6;// b
            punpcklbw mm2,mm6;// c
            punpcklbw mm3,mm6;// d

            //PXの計算。k-(zx shl 8);
            shl  edx,16;
            movd mm5,edx;
            movd mm4,ecx;
            psubd mm4,mm5;
            psrld mm4,8;

            //αを広げておく
            punpcklwd mm4,mm4;// $00aa > $00aa00aa
            punpckldq mm4,mm4;// $00aa00aa > $00aa00aa 00aa00aa
            movq  mm5,mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

	    //(px*py*(a+d-b-c) shr 8)+px*(b-a)+py*(c-a)) shr 8)+a;
            pmullw mm0, mm5; // a * px
            pmullw mm1, mm5; // c * px
            pmullw mm2, mm4; // b * (1 - px)
            pmullw mm3, mm4; // d * (1 - px)

            //PYの計算。といっても計算済み。
            movd mm4,l3; // a_dy
            punpcklwd mm4,mm4; //ワードからダブルワードへ
            punpckldq mm4,mm4; // 0x00bb00bb 00bb00bb
            movq mm5, mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

            //続き。
            paddusw mm0, mm2;  // (a * px + b * (1 - px))
            paddusw mm1, mm3;  // (c * px + d * (1 - px))
            psrlw mm0, 8;
            psrlw mm1, 8;
            pmullw mm0, mm5; // (a * px + b * (1 - px)) * py
            pmullw mm1, mm4; // (c * px + d * (1 - px)) * (1 - py)
            paddusw  mm0, mm1;  //
            psrlw    mm0, 8;
            packuswb mm0, mm6; // 0x00 00 00 00 B1' R0' G0' B0'

            //出力の準備
            movd dword ptr[ebx],mm0;
            add ebx,4;

            //Kを増やす。
            add ecx,mzoomx;

            dec eax;

            jne @LOOP1;

        //引き続き右端の特殊ループ、。

        //カウンター。
        mov eax,ew2;

        //あまっているのは、ecx,edx
        //mov ecx,ix8_2;//位置の絶対位置情報と値の保持

        //戻す
        sub ecx,mzoomx;


        @LOOP2:
         //取得位置を指定。

            //元画像の位置を計算。
            mov edx,ecx;
            shr edx,16;

            //元画像のポインタを移動
            //元画像の入力(64ビット入力。)
            movq mm0,qword ptr[edi+edx*4];
            movq mm1,qword ptr[esi+edx*4];
            movq mm2,mm0;
            movq mm3,mm1;

            //元画像を整頓
            psrlq mm2,32;
            psrlq mm3,32;

            //QWORDに広げて計算できるようにする。
            punpcklbw mm0,mm6;// a
            punpcklbw mm1,mm6;// c
            punpcklbw mm2,mm6;// b
            punpcklbw mm3,mm6;// d

            //PXの計算。k-(zx shl 8);
            shl  edx,16;
            movd mm4,ecx;
            movd mm5,edx;
            psubd mm4,mm5;
            psrld mm4,8;

            //αを広げておく
            punpcklwd mm4,mm4;// $00aa > $00aa00aa
            punpckldq mm4,mm4;// $00aa00aa > $00aa00aa 00aa00aa
            movq  mm5,mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

	    //(px*py*(a+d-b-c) shr 8)+px*(b-a)+py*(c-a)) shr 8)+a;
            pmullw mm0, mm5; // a * px
            pmullw mm1, mm5; // c * px
            pmullw mm2, mm4; // b * (1 - px)
            pmullw mm3, mm4; // d * (1 - px)

            //PYの計算。といっても計算済み。
            movd mm4,l3; // a_dy
            punpcklwd mm4,mm4; //ワードからダブルワードへ
            punpckldq mm4,mm4; // 0x00bb00bb 00bb00bb
            movq mm5, mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

            //続き。
            paddusw mm0, mm2;  // (a * px + b * (1 - px))
            paddusw mm1, mm3;  // (c * px + d * (1 - px))
            psrlw mm0, 8;
            psrlw mm1, 8;
            pmullw mm0, mm5; // (a * px + b * (1 - px)) * py
            pmullw mm1, mm4; // (c * px + d * (1 - px)) * (1 - py)
            paddusw  mm0, mm1;  //
            psrlw    mm0, 8;
            packuswb mm0, mm6; // 0x00 00 00 00 B1' R0' G0' B0'

            //出力の準備
            movd dword ptr[ebx],mm0;
            add ebx,4;
            
            //Kを増やす。
            add ecx,mzoomx;

            dec eax;

            jne @LOOP2;


        emms;
        pop esi;pop edi;pop edx;pop ecx;pop ebx;pop eax;    // レジスタ復活
      end;

      //次への位置をずらす。
      l:=l+mzoomy;
  end;


  if InBMP.Height>iy+ih then exit;

  zy:=iy+ih-1;
  l:=(ih-1)*($FFFF+1);


  for y:=oy+th to oy+oh-1 do begin
      pBit2:=OutBMP.ScanLine[y];


      ///現在の入力画像の高さ位置を計算
      //if zy<>iy+(l shr 8) then begin
      //   zy:=iy+(l shr 8);

         pBitN :=InBMP.ScanLine[zy-1];
         pBit:=InBMP.ScanLine[zy];
      //end;
      //バイリニアの割合（Y方向）
      l3:=(l-((l shr 16) shl 16))shr 8;//py


      asm
        push eax;push ebx;push ecx;push edx;push edi;push esi; // レジスタ退避

        //ピクセル位置
        mov edi,pBit;//Src
        mov esi,pBitN;//Src+1
        mov ebx,pBit2;//Dest

        //カウンター。
        mov eax,ew;

        //位置を調整。
        add ebx,ox4;


        //あまっているのは、ecx,edx
        mov ecx,ix8;//位置の絶対位置情報と値の保持

        //初期化
        pxor mm6,mm6;
        movd mm7,iMM4;//mm7には、$00FF00FFが入る。
        punpckldq mm7,mm7;//$00FF00FF 00FF00FFとコピーする。dword>qword

        //まずは、通常のループです。
        @LOOP1:
         //取得位置を指定。

            //元画像の位置を計算。
            mov edx,ecx;
            shr edx,16;

            //元画像のポインタを移動
            //元画像の入力(64ビット入力。)
            movq mm2,qword ptr[edi+edx*4];
            movq mm3,qword ptr[esi+edx*4];
            movq mm0,mm2;
            movq mm1,mm3;

            //元画像を整頓
            psrlq mm2,32;
            psrlq mm3,32;

            //QWORDに広げて計算できるようにする。
            punpcklbw mm0,mm6;// a
            punpcklbw mm1,mm6;// b
            punpcklbw mm2,mm6;// c
            punpcklbw mm3,mm6;// d

            //PXの計算。k-(zx shl 8);
            shl  edx,16;
            movd mm4,ecx;
            movd mm5,edx;
            psubd mm4,mm5;
            psrld mm4,8;

            //αを広げておく
            punpcklwd mm4,mm4;// $00aa > $00aa00aa
            punpckldq mm4,mm4;// $00aa00aa > $00aa00aa 00aa00aa
            movq  mm5,mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

	    //(px*py*(a+d-b-c) shr 8)+px*(b-a)+py*(c-a)) shr 8)+a;
            pmullw mm0, mm5; // a * px
            pmullw mm1, mm5; // c * px
            pmullw mm2, mm4; // b * (1 - px)
            pmullw mm3, mm4; // d * (1 - px)

            //PYの計算。といっても計算済み。
            movd mm4,l3; // a_dy
            punpcklwd mm4,mm4; //ワードからダブルワードへ
            punpckldq mm4,mm4; // 0x00bb00bb 00bb00bb
            movq mm5, mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

            //続き。
            paddusw mm0, mm2;  // (a * px + b * (1 - px))
            paddusw mm1, mm3;  // (c * px + d * (1 - px))
            psrlw mm0, 8;
            psrlw mm1, 8;
            pmullw mm0, mm5; // (a * px + b * (1 - px)) * py
            pmullw mm1, mm4; // (c * px + d * (1 - px)) * (1 - py)
            paddusw  mm0, mm1;  //
            psrlw    mm0, 8;
            packuswb mm0, mm6; // 0x00 00 00 00 B1' R0' G0' B0'

            //出力の準備
            movd dword ptr[ebx],mm0;
            add ebx,4;

            //Kを増やす。
            add ecx,mzoomx;

            dec eax;

            jne @LOOP1;

        //引き続き右端の特殊ループ、。

        //カウンター。
        mov eax,ew2;

        //あまっているのは、ecx,edx
        //mov ecx,ix8_2;//位置の絶対位置情報と値の保持

        //戻す
        sub ecx,mzoomx;

        @LOOP2:
         //取得位置を指定。

            //元画像の位置を計算。
            mov edx,ecx;
            shr edx,16;

            //元画像のポインタを移動
            //元画像の入力(64ビット入力。)
            movq mm0,qword ptr[edi+edx*4];
            movq mm1,qword ptr[esi+edx*4];
            movq mm2,mm0;
            movq mm3,mm1;

            //元画像を整頓
            psrlq mm2,32;
            psrlq mm3,32;

            //QWORDに広げて計算できるようにする。
            punpcklbw mm0,mm6;// a
            punpcklbw mm1,mm6;// c
            punpcklbw mm2,mm6;// b
            punpcklbw mm3,mm6;// d

            //PXの計算。k-(zx shl 8);
            shl  edx,16;
            movd mm4,ecx;
            movd mm5,edx;
            psubd mm4,mm5;
            psrld mm4,8;

            //αを広げておく
            punpcklwd mm4,mm4;// $00aa > $00aa00aa
            punpckldq mm4,mm4;// $00aa00aa > $00aa00aa 00aa00aa
            movq  mm5,mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

	    //(px*py*(a+d-b-c) shr 8)+px*(b-a)+py*(c-a)) shr 8)+a;
            pmullw mm0, mm5; // a * px
            pmullw mm1, mm5; // c * px
            pmullw mm2, mm4; // b * (1 - px)
            pmullw mm3, mm4; // d * (1 - px)

            //PYの計算。といっても計算済み。
            movd mm4,l3; // a_dy
            punpcklwd mm4,mm4; //ワードからダブルワードへ
            punpckldq mm4,mm4; // 0x00bb00bb 00bb00bb
            movq mm5, mm7;//反転用mm7
            psubw mm5,mm4;//反転完了。

            //続き。
            paddusw mm0, mm2;  // (a * px + b * (1 - px))
            paddusw mm1, mm3;  // (c * px + d * (1 - px))
            psrlw mm0, 8;
            psrlw mm1, 8;
            pmullw mm0, mm5; // (a * px + b * (1 - px)) * py
            pmullw mm1, mm4; // (c * px + d * (1 - px)) * (1 - py)
            paddusw  mm0, mm1;  //
            psrlw    mm0, 8;
            packuswb mm0, mm6; // 0x00 00 00 00 B1' R0' G0' B0'

            //出力の準備
            movd dword ptr[ebx],mm0;
            add ebx,4;

            //Kを増やす。
            add ecx,mzoomx;

            dec eax;

            jne @LOOP2;


        emms;
        pop esi;pop edi;pop edx;pop ecx;pop ebx;pop eax;    // レジスタ復活
      end;

      //次への位置をずらす。
      l:=l+mzoomy;
  end;

  inBMP.Handle:=outBMP.ReleaseHandle;
  outBMP.Free();
 // inBMP.PixelFormat:=pf32bit;

end;

function SuperTextOut(ToBMP:TBitmap;X,Y:Integer;bFont:TFont;Msg:String):TPoint;
var x2,y2,x3:Integer;//ループ用
    Pr :Integer;//加算平均値
    BMP      :TBitmap;
    Size     :TSize;
    pABit    :array[0..1] of PByteArray;
    W,H      :Integer;//幅
    iA,iA2   :DWORD;
    k3,k4:Integer;//先に計算してしまう
    r,g,b    :byte;
    li    :LongInt;
    PBit3: PRGBAArray;
    rgba:TRGBA;
begin
   li:=ColorToRGB(bFont.Color);

   b:=(li and $000000FF);
   g:=(li and $0000FF00) shr 8;
   r:=(li and $00FF0000) shr 16;


 //クリエイト
 BMP:=TBitmap.Create;
 try

  //設定を代入
  BMP.Canvas.Font.Name:=bFOnt.Name;
  BMP.Canvas.Font.Size:=bFOnt.Size*2;
  BMP.Canvas.Font.Style:=bFont.Style;
  BMP.Canvas.Font.Charset:=bFont.Charset;

  //サイズは小さいほうに合わせる
  Size:=BMP.Canvas.TextExtent(Msg);

  //幅の設定
  W:=(Size.cx div 2);
  H:=(Size.cy div 2);

  BMP.PixelFormat  := pf32Bit;
  //サイズを確定
  BMP.Width  :=W*2+1;
  BMP.Height :=H*2+1;



  //文字描画
  BMP.Canvas.Brush.Style:=bsClear;
  BMP.Canvas.Font.Color :=clBlack;
  BMP.Canvas.TextOut(0,0,msg);


  k3:=1;

  //幅とのクリッピング計算

  if x+w>ToBMP.Width then begin
     w:=ToBMP.Width-x;
  end;

  if y+h>ToBMP.Height then begin
     h:=ToBMP.Height-y;
  end;



  for y2:=0 to h-1 do begin

      //Ｙラインの取得
      Pbit3:=ToBMP.ScanLine[y2+y];

      //外に置いて高速化

      //スキャンライン取得を前で実行
      pABit[0]:=BMP.ScanLine[k3];
      inc(k3);
      pABit[1]:=BMP.ScanLine[k3];
      inc(k3);


      //先に計算
      x3:=x;
      k4:=0;

      for x2:=0 to w-1 do begin

          //ＲＧＢの取得

             //読み込み
             Pr:=0;

             inc(pr,PABit[0][k4]);
             inc(pr,PABit[0][k4+4]);
             inc(pr,PABit[1][k4]);
             inc(pr,PABit[1][k4+4]);


             //平均値を出す
             //書き込み
             iA:=(pr shr 2)+1;
             iA2:=256-iA;

             rgba:=pBit3[x3];
             rgba.r:=(rgba.r*iA+r*iA2) shr 8;
             rgba.g:=(rgba.g*iA+g*iA2) shr 8;
             rgba.b:=(rgba.b*iA+b*iA2) shr 8;
             

             pBit3[x3]:=rgba;
             inc(x3);
             inc(k4,8);
      end;
  end;



  finally
    //解放
    BMP.Free;
  end;

  result:=Point(x+w,y);

end;







end.
