unit s_MathPack;

//SANDMANのための演算パッケージ


// 参考資料
//
// AMD社      3DNow! テクノロジマニュアル
//            AMD K6-2 Processor Code Optimization
//            AMD Processor Recognition
//
//一部のルーチンの作成にあたって、AMD-3D SDKを参考にしましたm(__)m



interface

uses
  s_3DNow,d3dtypes,Windows;

//↓の一行をコメントアウトすれば、3DNow!を使わないコードになります
//{$DEFINE USE_3DNOW}

type
  PSingle = ^Single;

//ベクトル(2D)
type TVector2D = packed record
  X,Y:Single;
end;
PVector2D = ^TVector2D;


//3次元のベクトルはD3DVector、ね。


//同次3次元のベクトル(同次なので4つ要素があります)
type THgVector = packed record
  X,Y,Z,W:Single;
end;
PHgVector = ^THgVector;


//クォータニオン(THgVectorとはあえて互換性を持たせない)
type TQuaternion = packed record
  case Integer of
    0: (X,Y,Z,W:Single);
end;
PQuaternion = ^TQuaternion;


//BOX
type TBox3D = packed record
  Min,Max:D3DVector;
end;


//同次行列…は、D3DMATRIX

const
  //単位行列
  NowIdentityMatrix:D3DMATRIX = ( _11:1; _12:0; _13:0; _14:0;
                                  _21:0; _22:1; _23:0; _24:0;
                                  _31:0; _32:0; _33:1; _34:0;
                                  _41:0; _42:0; _43:0; _44:1);

  //ゼロ行列
  NowZeroMatrix:D3DMATRIX = (     _11:0; _12:0; _13:0; _14:0;
                                  _21:0; _22:0; _23:0; _24:0;
                                  _31:0; _32:0; _33:0; _34:0;
                                  _41:0; _42:0; _43:0; _44:0);

///////////////////////////////////////////////////////////////////////////////
// 3DNow!演算パッケージ
//
// Delphiにおける、引数の取り扱いについての注意
//
// EAX ... 第一引数
// EDX ... 第二引数
// ECX ... 第三引数または返り値
//
// var,constで引数が宣言されているならポインタ扱い。
// 返り値は、recordの場合、返り値へのポインタ
// 単純型の場合は、整数型はそのままでOK、実数型はST(0)に積む
//
// 4つ以上の引数がある場合は、スタックに積まれる。
// 尚、手続きに突入する際に、mov ebp,esp が行われるので、ebpを使って参照可
///////////////////////////////////////////////////////////////////////////////



//まずこれを呼ぶべし
procedure NowInit;


//////////////////////コンストラクタ
function  Vector2D(_x,_y:Single):TVector2D;
function  Vector(_x,_y,_z:Single):D3DVECTOR;
function  HgVector(_x,_y,_z,_w:Single):THgVector;
function  Quaternion(_w,_x,_y,_z:Single):TQuaternion;

//////////////////////色調
function NowScaleColor(const col:DWord; const scale:Single):DWord;
function NowAddColor(const col1:DWord; const col2:DWord):DWord;


//////////////////////変換

//Int <--> Single 変換(端数切捨て)
function  NowItoF2D(const a:TPoint):TVector2D;
function  NowFtoI2D(const a:TVector2D):TPoint;

//Int <--> Single 変換(端数四捨五入)
function  NowRound2D(const a:TVector2D):TPoint;

//同次ベクトルと普通のベクトルの変換
function  NowHomoginize(const a:D3DVector):THgVector;   //W=1を付けるだけ
function  NowHeteroginize(const a:THgVector):D3DVector; //Wを捨てるだけ

//ベクトルからLVertexを作る
function  NowLVfromVector(const a:D3DVector; color,specular:DWord; tu,tv:Single):D3DLVERTEX;

//同次ベクトルから
function  NowTLVfromHgVector(const a:THgVector; color,specular:DWord; tu,tv:Single):D3DTLVERTEX;

//LVからTLVへ
function  NowLVToTLV(const lv:D3DLVERTEX; const transMat:D3DMATRIX):D3DTLVERTEX;
procedure NowLVToTLVBatch(src:LPD3DLVERTEX; dest:LPD3DTLVERTEX; const transMat:D3DMATRIX; count:Integer);

//角度系の変換
//function NowDegree():Integer; //360度系から、4096度系へ




//////////////////////補間

//スプライン補間(4点を与えられて、中間2点のブレンド比を与えて補間
procedure NowInterpolate(var dest:Single; const p1,p2,p3,p4:Single; const rate:Single);

//線形補間
procedure NowLerp(var dest:Single; const p1,p2:Single; const rate:Single);




//////////////////////2D演算

//ベクトルの足し算
function NowAdd2D(const a:TVector2D; const b:TVector2D):TVector2D;

//ベクトルの引き算
function NowSub2D(const a:TVector2D; const b:TVector2D):TVector2D;

//内積
procedure NowDotProduct2D(var dest:Single; const a:TVector2D; const b:TVector2D);

//2点の距離
procedure NowDistance2D(var dest:Single; const a,b:TVector2D);

//長さを算出
procedure NowLength2D(var dest:Single; const a:TVector2D);

//ベクトルの向きを4096度系で
procedure NowVecToAngle2D(var dest:Integer; const a:TVector2D);

//回転(原点を右回りにangleだけ)
function NowRot2D(const a:TVector2D; const angle:Integer):TVector2D;

//正規化(長さを1に)
function NowNormalize2D(const a:TVector2D):TVector2D;

//スケーリング
function NowScale2D(const a:TVector2D; const scale:Single):TVector2D;

//ベクトルの長さをkにする
function NowChangeLength2D(const a:TVector2D; const k:Single):TVector2D;

//posからtargetに向いた長さkのベクトルを生成
function NowLookAt2D(const pos:TVector2D; const target:TVector2D; const k:Single):TVector2D;

//長さkのランダムなベクトルを作る
function NowRandom2D(const k:Single):TVector2D;



//////////////////////3D演算(ベクトル)

//足し算
function NowAdd(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
function NowAddHg(const a:THgVector; const b:THgVector):THgVector;

//引き算
function NowSub(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
function NowSubHg(const a:THgVector; const b:THgVector):THgVector;

//内積
procedure NowDotProduct(var dest:Single; const a:D3DVECTOR; const b:D3DVECTOR);

//外積
function NowCrossProduct(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;


//2点の距離
procedure NowDistance(var dest:Single;  const a,b:D3DVECTOR);

//原点回りの回転(各軸を左回りに)
function NowRotX(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
function NowRotY(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
function NowRotZ(const a:D3DVECTOR; const t:Integer):D3DVECTOR;

//ベクトルの反転
function NowNeg(const a:D3DVECTOR):D3DVECTOR;

//正規化
function NowNormalize(const a:D3DVECTOR):D3DVECTOR;

//長さを得る
procedure NowLength(var dest:Single; const a:D3DVECTOR);

//スケーリング
function NowScale(const a:D3DVECTOR; const scale:Single):D3DVECTOR;

//長さを k に
function NowChangeLength(const a:D3DVECTOR; const k:Single):D3DVECTOR;

//posからtargetに向いた長さkのベクトルを生成
function NowLookAt(const pos:D3DVECTOR; const target:D3DVECTOR; const k:Single):D3DVECTOR;

//正規化除算(x,y,z,w) → (x/w, y/w, z/w, 1/w)
function NowViewFrustumToScreen(const a:THgVector):THgVector;




//////////////////////3D演算(クォータニオン)

//足し算
function NowAddQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;

//引き算
function NowSubQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;

//乗算
function NowMulQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;

//内積
procedure NowDotQuat(var dest:Single; const a:TQuaternion; const b:TQuaternion);

//ノルム
procedure NowLengthQuat(var dest:Single; const a:TQuaternion);

//正規化
function NowNormalizeQuat(const a:TQuaternion):TQuaternion;

//axis回りの回転を表すクォータニオンを作る
function  NowQuatFromRotation(const axis:D3DVECTOR; const t:Integer):TQuaternion;

//クォータニオンから行列を作る
function  NowMatrixFromQuat(const a:TQuaternion):D3DMATRIX;

//axis回りの回転を表す行列を作る(QuatFromRotationとMatrixFromQuatの合成)
function  NowMatrixFromRotation(const axis:D3DVECTOR; const t:Integer):D3DMATRIX;

//Slerp
function  NowSlerpQuat(const a:TQuaternion; const b:TQuaternion; const rate:Single):TQuaternion;


//////////////////////3D演算(マトリクス)

//ベクトルを変換(同次)
function NowTransform(const a:THgVector; const m:D3DMATRIX):THgVector;

//一気にベクトルを変換
procedure NowTransformBatch(const src:Pointer; const m:D3DMATRIX; const num:Integer; const span:Integer);

//透視射影行列を作る
function NowProjectFrustum(const halfWidth:Single; const halfHeight:Single; const nearZ:Single; const farZ:Single):D3DMATRIX;

//カメラとターゲットの位置から、ビュー行列を作る
function NowViewMatrix(const from:D3DVECTOR; const at:D3DVECTOR; const world_up:D3DVECTOR; const roll:Integer):D3DMATRIX;

//姿勢・位置からビュー行列を作る
function NowViewMatixFromOrientation(const from:D3DVECTOR; const dir:D3DVECTOR; const up:D3DVECTOR):D3DMATRIX;


//逆行列
function NowInvMatrix(const m:D3DMATRIX):D3DMATRIX;

//転置行列
function NowTMatrix(const m:D3DMATRIX):D3DMATRIX;

//回転部分だけ抜き出し
function NowExtractRotation(const m:D3DMATRIX):D3DMATRIX;

//平行移動部分だけ抜き出し
function NowExtractTranslation(const m:D3DMATRIX):D3DMATRIX;


//マトリクスの合成
function NowCompositeMatrix(const m:D3DMATRIX; const n:D3DMATRIX):D3DMATRIX;

//回転行列
function NowRotXMatrix(const t:Integer):D3DMATRIX;
function NowRotYMatrix(const t:Integer):D3DMATRIX;
function NowRotZMatrix(const t:Integer):D3DMATRIX;

//スケーリング・平行移動行列
function NowScaleMatrix(const x,y,z:Single):D3DMATRIX;
function NowTranslateMatrix(const x,y,z:Single):D3DMATRIX;

//Sin,Cosテーブル(4096度系)
var
  NowSinT:packed Array[0..4095] of Single;
  NowCosT:packed Array[0..4095] of Single;
  NowSinCosT:packed Array[0..4095] of TVector2D;   //Sin Cos
  NowCosSinT:packed Array[0..4095] of TVector2D;   //Cos Sin
  NowCosNSinT:packed Array[0..4095] of TVector2D;  //Cos -Sin
  NowNSinCosT:packed Array[0..4095] of TVector2D;  //-Sin Cos


implementation

const
  PNowSinT:Pointer = @NowSinT;
  PNowCosT:Pointer = @NowCosT;
  PNowSinCosT:Pointer = @NowSinCosT;
  PNowCosSinT:Pointer = @NowCosSinT;
  PNowCosNSinT:Pointer = @NowCosNSinT;
  PNowNSinCosT:Pointer = @NowNSinCosT;



//テーブルや変数の初期化(Initializationで呼ばれる…けど)
procedure NowInit;
var
  s,c:Single;
  i:Integer;
  real_i:Single;
begin

  //WriteLn('テーブル作成ルーチンを通りました');
  //三角関数テーブルの作成
  For i:=0 to 4095 do begin
    real_i:=i;
    s:=Sin(real_i / 2048.0 * Pi);
    c:=Cos(real_i / 2048.0 * Pi);

    NowSinT[i]:=s;
    NowCosT[i]:=c;

    NowSinCosT[i]:=Vector2D(s,c);
    NowCosSinT[i]:=Vector2D(c,s);
    NowCosNSinT[i]:=Vector2D(c,-s);
    NowNSinCosT[i]:=Vector2D(-s,c);
  end;

end;



/////////////////////////////////////
// 各種構造体の初期化
/////////////////////////////////////
function Vector2D(_x,_y:Single):TVector2D;
begin
  result.X:=_x;
  result.Y:=_y;
end;

function Vector(_x,_y,_z:Single):D3DVECTOR;
begin
  result.X:=_x;
  result.Y:=_y;
  result.Z:=_z;
end;

function HgVector(_x,_y,_z,_w:Single):THgVector;
begin
  result.X:=_x;
  result.Y:=_y;
  result.Z:=_z;
  result.W:=_w;
end;


function Quaternion(_w,_x,_y,_z:Single):TQuaternion;
begin
  result.W:=_w;
  result.X:=_x;
  result.Y:=_y;
  result.Z:=_z;
end;



///////////////////////////////////
// 色調
///////////////////////////////////

function NowScaleColor(const col:DWord; const scale:Single):DWord;
var
  scale2:DWord;
  r,g,b:Integer;
begin
  scale2:=Round(scale * 256.0);

  if scale <= 0.0 then begin
    Result:=0;
    exit;
  end;

  r:=col And $00FF0000 Shr 16 * scale2 Shr 8;
  if r < 0 then
    r:=0
  else if r > 255 then
    r:=255;

  g:=col And $0000FF00 Shr 8 * scale2 Shr 8;
  if g < 0 then
    g:=0
  else if g > 255 then
    g:=255;

  b:=col And $000000FF * scale2 Shr 8;
  if b < 0 then
    b:=0
  else if b > 255 then
    b:=255;


  result:=
    col And $FF000000 Or
    DWord(r) Shl 16 Or
    DWord(g) Shl 8 Or
    DWord(b);
end;

function NowAddColor(const col1:DWord; const col2:DWord):DWord;
var
  c,d:DWord;
begin

  c:=col1 And $00FEFEFE + col2 And $00FEFEFE;
  d:=c;

  c:=c And $01010100;   //桁上がり検出マスク
  c:=c - c Shr 8;       //桁上がりをしたところは、0xffになる

  result := c Or d Or $FF000000;

end;


///////////////////////////////////
// 変換関数
///////////////////////////////////

//同次ベクトルと普通のベクトルの変換
function  NowHomoginize(const a:D3DVector):THgVector;
begin
  Move(a,result,Sizeof(D3DVector));
  result.W:=1.0;
end;

function  NowHeteroginize(const a:THgVector):D3DVector;
begin
  Move(a,result,Sizeof(D3DVector));
end;

//ベクトルからLVertexを作る
function  NowLVfromVector(const a:D3DVector; color,specular:DWord; tu,tv:Single):D3DLVERTEX;
begin
  Move(a,result,Sizeof(D3DVector));
  result.dwReserved:=0;
  result.color:=color;
  result.specular:=specular;
  result.tu:=tu;
  result.tv:=tv;
end;

//同次ベクトルからTLVertex
function  NowTLVfromHgVector(const a:THgVector; color,specular:DWord; tu,tv:Single):D3DTLVERTEX;
begin
  Move(a,result,Sizeof(THgVector));
  result.color:=color;
  result.specular:=specular;
  result.tu:=tu;
  result.tv:=tv;
end;


{$IFDEF USE_3DNOW}

/////////////////////////////////////
// Int <--> Float 変換
/////////////////////////////////////
function  NowItoF2D(const a:TPoint):TVector2D;
begin
  asm
    DW    FEMMS;

    //mov   eax,a;
    DW    MOVQ_ld;      DB MM0_mEAX;
    //mov   edx,@result;
    DW    _3DNow;       DB MM0_MM0;   DB PI2FD;
    DW    MOVQ_st;      DB MM0_mEDX;

    DW    FEMMS;
  end;
end;

function  NowFtoI2D(const a:TVector2D):TPoint;
begin
  asm
    DW  FEMMS;

    //mov   eax,a;
    DW    MOVQ_ld;      DB MM0_mEAX;
    //mov   edx,@result;
    DW    _3DNow;       DB MM0_MM0;   DB PF2ID;
    DW    MOVQ_st;      DB MM0_mEDX;

    DW  FEMMS;
  end;
end;


//四捨五入
function  NowRound2D(const a:TVector2D):TPoint;
begin
  asm
    DW  FEMMS;

    mov   ecx,$3F000000;  //0.5
    //mov   eax,a;
    DW    MOVQ_ld;      DB MM0_mEAX;
    DW    MOVD_ld;      DB MM1_ECX;
    DW    PUNPCKLDQ;    DB MM1_MM1;
    DW    _3DNow;       DB MM0_MM1;   DB PFADD;
    DW    _3DNow;       DB MM0_MM0;   DB PF2ID;
    DW    MOVQ_st;      DB MM0_mEDX;

    DW  FEMMS;
  end;
end;


//LVからTLVへ
function  NowLVToTLV(const lv:D3DLVERTEX; const transMat:D3DMATRIX):D3DTLVERTEX;
var
  hg:THgVector;  //頂点座標
begin
  Move(lv,hg,Sizeof(D3DVERTEX));
  hg.W:=1;

  hg:=NowViewFrustumToScreen(NowTransform(hg,transMat));
  Move(hg,result,sizeof(THgVector));
  Move(lv.color,result.color,sizeof(D3DTLVERTEX) - sizeof(THgVector));

end;

//LVからTLVへ、バッチ変換
procedure NowLVToTLVBatch(src:LPD3DLVERTEX; dest:LPD3DTLVERTEX; const transMat:D3DMATRIX; count:Integer);
begin
  asm
    DW      FEMMS;
    push    ebx
    push    edi


    mov     eax,src;
    mov     ebx,dest
    mov     ecx,count
    mov     edx,transMat
    mov     edi,$3F800000;    //1.0

    and     ecx,ecx;
    jz      @END



    @TOP:
    test  ecx,4;
    jnz   @NEXT;
    DW    PREFETCHW;  DB mm1_bEAX;  DB 128;
    DW    PREFETCHW;  DB mm1_bEBX;  DB 128;
    @NEXT:

    //まず、変換
    DW    movq_ld;    DB mm0_mEAX;		          // ay, ax	in mm0
    DW    movd_ld;    DB mm2_edi;
    DW    movd_ld;    DB mm1_bEAX;  DB 8;
    DW    punpckldq;  DB mm1_mm2;               //  1, az	in mm1

    //
    DW    movq_ld;    DB mm4_mEDX;      		    // m01, m00	in mm4
    DW    punpckhdq;	DB mm2_mm0;		            // ay, undef	in mm2
    //
    DW    movq_ld;    DB mm5_bEDX;  DB 16;	    // m11, m10	in mm5
    DW    punpckldq;  DB mm0_mm0;       		    // ax, ax	in mm2
    //
    DW    movq_ld;    DB mm6_bEDX;  DB 32;      // m21, m20	in mm6
    DW    _3DNow;     DB mm4_mm0;   DB pfmul;   // ax*m01, ax*m00	in mm4
    //
    DW    movq_ld;    DB mm7_bEDX;  DB 48;      // m31, m30	in mm7
    DW    punpckhdq;  DB mm2_mm2;           		// ay, ay	in mm2
    //
    DW    punpckhdq;  DB mm3_mm1;           		// aw, undef	in mm3
    DW    _3DNow;     DB mm5_mm2;   DB pfmul; 	// ay*m11, ay*m10
    //
    DW    punpckldq;  DB mm1_mm1;           		// az, az	in mm3
    DW    _3DNow;     DB mm0_bEDX;  DB 8;   DB pfmul;   	// ax*m03, ax*m02 in mm0
    //
    DW    punpckhdq;  DB mm3_mm3;            		// aw, aw	in mm3
    DW    _3DNow;     DB mm2_bEDX;  DB 24;  DB PFMUL;     // ay*13, ay*m12	in mm2
    //
    DW    _3DNow;     DB mm6_mm1;   DB pfmul; 	// az*m21, az*m20	in mm6
    DW    _3DNow;     DB mm5_mm4;   DB pfadd;
    //
    DW    _3DNow;     DB mm1_bEDX;  DB 40;    DB pfmul    // az*23, az*22	in mm1
    DW    _3DNow;     DB mm2_mm0;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm3;   DB pfmul;   // aw*m31, aw*m30	in mm7
    DW    _3DNow;     DB mm6_mm5;   DB pfadd;
    //
    DW    _3DNow;     DB mm3_bEDX;  DB 56;    DB pfmul;   // aw*m33, aw*m32	in mm3
    DW    _3DNow;     DB mm2_mm1;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm6;   DB pfadd    // ry, rx	in mm7
    DW    _3DNow;     DB mm3_mm2;   DB pfadd		// rw,rz		in mm3

    //正規化除算
    DW    MOVQ_ld;    DB mm4_mm3;
    DW    PSXXimq;    DB mm4_SRLim; DB 32;
    DW    _3DNow;     DB mm4_mm4;   DB pfrcp;   // 1/rw  | 1/rw
    DW    _3DNow;     DB mm7_mm4;   DB pfmul;   // ry/rw | rx/rw
    DW    _3DNow;     DB mm3_mm4;   DB pfmul;   // rw/rw | rz/rw
    DW    punpckldq;  DB mm3_mm4;               // 1/rw  | rz/rw

    //格納


    //転送
    DW    MOVQ_ld;    DB mm0_bEAX;  DB 16;
    DW    MOVQ_ld;    DB mm1_bEAX;  DB 24;
    DW    MOVQ_st;    DB mm7_mEBX;
    DW    MOVQ_st;    DB mm3_bEBX;  DB 8;
    DW    MOVQ_st;    DB mm0_bEBX;  DB 16;
    DW    MOVQ_st;    DB mm1_bEBX;  DB 24;

    add   eax,32;
    add   ebx,32;


    dec   ecx
    jnz   @TOP

    @END:

    pop     edi
    pop     ebx
    DW      FEMMS;
  end;
end;


/////////////////////////////////////
// 1D計算パッケージ
/////////////////////////////////////

//3次Bスプライン補間(4点)
//4点のうち、中間2点のブレンド比を与えて補間。rateは0〜1で、大きいほど出力はp3に近づく
procedure NowInterpolate(var dest:Single; const p1,p2,p3,p4:Single; const rate:Single);
begin
  asm
    DW    FEMMS;

    //まず、ブレンド比の計算
    mov   eax,rate;
    DW    MOVD_ld;    DB MM0_EAX;                   //MM0 = rate
    mov   ecx,$3F800000;
    DW    MOVD_ld;    DB MM7_ECX;                   //MM7 = 1.0;
    DW    MOVQ_ld;    DB MM3_MM7;
    DW    _3DNow;     DB MM3_MM0;   DB PFSUB;
    DW    MOVQ_ld;    DB MM4_MM3;
    DW    _3DNow;     DB MM3_MM4;   DB PFMUL;
    DW    _3DNow;     DB MM3_MM4;   DB PFMUL;       //mm3 = (1-rate)^3
    DW    MOVQ_ld;    DB MM1_MM0;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;       //MM1 = rate^2
    DW    MOVQ_ld;    DB MM2_MM1;
    DW    _3DNow;     DB MM2_MM0;   DB PFMUL;       //MM2 = rate^3

    mov   ecx,$40400000;    //3.0
    DW    MOVQ_ld;    DB MM4_MM1;
    DW    MOVQ_ld;    DB MM5_MM2;
    DW    _3DNow;     DB MM4_MM4;   DB PFADD;
    mov   edx,$40800000     //4.0
    DW    _3DNow;     DB MM5_MM4;   DB PFSUB;
    DW    MOVD_ld;    DB MM4_ECX;
    DW    _3DNow;     DB MM4_MM5;   DB PFMUL;
    DW    MOVD_ld;    DB MM5_EDX;
    DW    _3DNow;     DB MM4_MM5;   DB PFADD;       //MM4 = 3t^3 - 6t^2 + 4

    DW    MOVQ_ld;    DB MM5_MM0;
    DW    _3DNow;     DB MM5_MM1;   DB PFADD;
    DW    _3DNow;     DB MM5_MM2;   DB PFSUB;
    DW    MOVD_ld;    DB MM6_ECX;
    DW    _3DNow;     DB MM5_MM6;   DB PFMUL;
    DW    _3DNow;     DB MM5_MM7;   DB PFADD;       //MM5 = 3(-t^3+t^2+t)+1

    DW    PUNPCKLDQ;  DB MM3_MM4;   // MM3 = r1 | r2
    DW    PUNPCKLDQ;  DB MM5_MM2;
    DW    MOVQ_ld;    DB MM0_MM5;   // MM0 = r3 | r4

    mov   eax,p1;
    mov   ecx,p2;
    DW    MOVD_ld;    DB MM2_EAX;
    DW    MOVD_ld;    DB MM4_ECX;
    DW    PUNPCKLDQ;  DB MM2_MM4;   // MM2 = p1 | p2

    mov   eax,p3;
    mov   ecx,p4;
    DW    MOVD_ld;    DB MM1_EAX;
    DW    MOVD_ld;    DB MM5_ECX;
    DW    PUNPCKLDQ;  DB MM1_MM5;   // MM1 = p3 | p4

    DW    _3DNow;     DB MM3_MM2;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;

    mov   ecx,$3E2AAAAB;    //1/6
    DW    _3DNow;     DB MM0_MM3;   DB PFADD;
    DW    MOVD_ld;    DB MM1_ECX;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;

    mov   eax,dest;
    DW    MOVD_st;    DB MM0_mEAX;


    DW    FEMMS;
  end;

end;

//線形補間(rateは２点のブレンド比で0〜1、1に近いほどp2が濃くなる。
procedure NowLerp(var dest:Single; const p1,p2:Single; const rate:Single);
begin
  asm
    push  ebx;

    DW    FEMMS;

    mov   eax,dest;
    mov   edx,p1
    mov   ecx,p2

    DW    MOVD_ld;    DB MM0_EDX;   //p1
    DW    MOVD_ld;    DB MM1_ECX;   //p2;
    DW    PUNPCKLDQ;  DB MM0_MM1;   //MM0 = p1 | p2

    mov   ecx,$3F800000;  //1.0
    mov   ebx,rate;
    DW    MOVD_ld;    DB MM7_ECX;   //MM7 = 1.0 | 0.0
    DW    MOVD_ld;    DB MM6_EBX;   //MM6 = rate
    DW    MOVD_ld;    DB MM5_EBX;
    DW    _3DNow;     DB MM7_MM5;   DB PFSUB;   //MM7 = 1.0-rate | 0
    DW    PUNPCKLDQ;  DB MM7_MM6;   //MM7 = 1.0-rate | rate

    DW    _3DNow;     DB MM0_MM7;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
    pop   ebx;
  end;
end;


/////////////////////////////////////
// 2D計算パッケージ
/////////////////////////////////////

//ベクトルの足し算
function NowAdd2D(const a:TVector2D; const b:TVector2D):TVector2D;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_mEDX;

    DW    _3DNow;     DB MM0_MM1;   DB PFADD;

    DW    MOVQ_st;    DB MM0_mECX;

    DW    FEMMS;
  end;

end;



//ベクトルの引き算
function NowSub2D(const a:TVector2D; const b:TVector2D):TVector2D;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_mEDX;

    DW    _3DNow;     DB MM0_MM1;   DB PFSUB;

    DW    MOVQ_st;    DB MM0_mECX;

    DW    FEMMS;
  end;
end;


//内積
procedure NowDotProduct2D(var dest:Single; const a:TVector2D; const b:TVector2D);
begin

  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEDX;
    DW    MOVQ_ld;    DB MM1_mECX;

    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;

end;


//2点の距離
procedure NowDistance2D(var dest:Single; const a,b:TVector2D);
begin
  asm

    DW    FEMMS

    //読みこみ
    DW    MOVQ_ld;  DB    MM0_mEDX;
    DW    MOVQ_ld;  DB    MM1_mECX;

    //減算
    DW    _3DNow;   DB    MM0_MM1;    DB    PFSUB

    //自乗
    DW    _3DNow;   DB    MM0_MM0;    DB    PFMUL

    //上位と下位の加算
    DW    _3DNow;   DB    MM0_MM0;    DB    PFACC

    //平方根
    DW    _3DNow;   DB    MM1_MM0;    DB    PFRSQRT
    DW    _3DNow;   DB    MM0_MM1;    DB    PFMUL

    //結果の格納
    DW    MOVD_st;  DB    MM0_mEAX;


    DW    FEMMS
  end;
end;




//長さ
procedure NowLength2D(var dest:Single; const a:TVector2D);
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEDX;
    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM0;   DB PFRSQRT;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;
end;


//スケーリング
function NowScale2D(const a:TVector2D; const scale:Single):TVector2D;
begin
  asm
    DW    FEMMS;

    mov   eax,a;
    mov   edx,[scale];
    DW    MOVD_ld;    DB MM1_EDX;
    DW    MOVQ_ld;    DB MM0_mEAX;

    DW    PUNPCKLDQ;  DB MM1_MM1;

    DW    _3DNow;     DB MM0_MM1;   DB  PFMUL;

    mov   ecx,@result;
    DW    MOVQ_st;    DB MM0_mECX;

    DW    FEMMS;
  end;
end;


//ベクトルの向きを4096度系で
procedure NowVecToAngle2D(var dest:Integer; const a:TVector2D);
var
  v:TVector2D;
  pv:PVector2D;
  sg:Integer;   //象限
  mid:Integer;  //2分探索用
begin
  v:=a;
  pv:=@v;

  //象限はどれ？
  {
  if (v.y > 0) then begin
    if v.x > 0 then
      sg:=1
    else begin
      sg:=2;
      v.x:=-v.x;
    end;
  end else if (v.y < 0) then begin
    if v.x >= 0 then
      sg:=4
    else begin
      sg:=3;
      v.x:=-v.x;
    end;
  end else begin
    if v.x >= 0 then
      sg:=1
    else begin
      sg:=3;
      v.x:=-v.x;
    end;
  end;
  }
  

  asm
    push  eax;
    push  ebx;
    push  edx;
    push  edi;
    DW    FEMMS;

    mov   edx,pv;

    //象限はどれ?
    DW    PXOR;       DB MM1_MM1;
    DW    MOVQ_ld;    DB MM0_mEDX;
    DW    MOVQ_ld;    DB MM7_MM0;

    DW    MOVQ_ld;    DB MM2_MM0;
    DW    _3DNow;     DB MM0_MM1;   DB PFCMPGE;   //v.x >= 0 ?
    DW    MOVD_st;    DB MM0_EAX;
    and   eax,eax;
    jnz   @PLUS_X;
    // x < 0
    mov    sg,2;
    DW    _3DNow;     DB MM7_MM1;   DB PFSUBR;    //X軸反転
    jmp   @JUDGE_Y;

    // x >= 0
    @PLUS_X:
    mov    sg,1;


    @JUDGE_Y:
    DW    PUNPCKHDQ;  DB MM2_MM2;
    DW    _3DNow;     DB MM2_MM1;   DB PFCMPGE;   //v.y >= 0 ?
    DW    MOVD_st;    DB MM2_EAX;
    and   eax,eax;
    jnz   @PLUS_Y;
    // y < 0
    add   sg,2;
    @PLUS_Y:



    //ノーマライズ

    DW    MOVQ_ld;  DB MM0_MM7;
    DW    MOVQ_ld;  DB MM2_MM0;
    DW    _3DNow;   DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;   DB MM0_MM0;   DB PFACC;     //2乗和
    DW    MOVQ_ld;  DB MM4_MM0;
    DW    _3DNow;   DB MM0_MM0;   DB PFRSQRT;   //これで、1/kがでる

    DW    MOVQ_ld;  DB MM1_MM0;
    DW    _3DNow;   DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;   DB MM4_MM1;   DB PFRSQIT1;
    DW    _3DNow;   DB MM4_MM0;   DB PFRCPIT2;

    DW    _3DNow;   DB MM4_MM2;   DB PFMUL;     //元の値と掛け算


    //Cosテーブル内を2分探索
    mov   ecx,1023;   //hi
    mov   ebx,0;      //lo
    mov   edx,511;    //mid


    @LOOP_TOP:

    DW    MOVQ_ld;  DB MM2_MM4;
    cmp   ecx,ebx;
    jle   @LOOP_END

    mov   eax,edx;
    shl   eax,2;
    add   eax,PNowCosT;

    DW    _3DNow;   DB MM2_mEAX;   DB PFCMPGE;   //v.x >= NowCosT[mid] ?
    DW    MOVD_st;  DB MM2_EDI;
    and   edi,edi
    jz    @PATH1 //false then ...

    mov   ecx,edx;  //hi = mid
    add   edx,ebx;
    shr   edx,1;    //mid = (hi + lo) / 2
    jmp   @LOOP_TOP;

    @PATH1:
    mov   ebx,edx;  //lo = mid + 1 , mid = (hi+lo)/2
    add   edx,ecx;
    shr   edx,1;
    inc   ebx;
    jmp   @LOOP_TOP;

    @LOOP_END:


    DW    FEMMS;

    mov   mid,edx;

    pop   edi;
    pop   edx;
    pop   ebx;
    pop   eax;


  end;

  //象限に応じて、結果を加工
  Case sg of
    1: dest:=mid;
    2: dest:=2047-mid;
    4: dest:=2048+mid;
    3: dest:=4095-mid;
  end;

end;

//回転
function NowRot2D(const a:TVector2D; const angle:Integer):TVector2D;
begin
  asm
    DW  FEMMS

    mov   eax,[angle];
    and   eax,4095;   //角度をノーマライズ
    mov   ecx,a;


    //読みこみ
    DW    MOVQ_ld;  DB MM2_mECX;
    DW    MOVQ_ld;  DB MM0_MM2;

    //MM2に、result.Xを求める
    mov   edx,PNowCosNSinT;
    shl   eax,3;
    add   edx,eax;
    DW    MOVQ_ld;  DB MM3_mEDX;
    DW    _3DNow;   DB MM2_MM3;   DB PFMUL;
    DW    _3DNow;   DB MM2_MM2;   DB PFACC;

    //MM0に、result.Yを求める
    mov   edx,PNowSinCosT;
    add   edx,eax;
    DW    MOVQ_ld;  DB MM3_mEDX;
    DW    _3DNow;   DB MM0_MM3;   DB PFMUL;
    DW    _3DNow;   DB MM0_MM0;   DB PFACC;

    //destに格納して終わり
    DW    PUNPCKHDQ;  DB MM2_MM0;
    mov   eax,@result;
    DW    MOVQ_st;    DB MM2_mEAX;

    DW  FEMMS

  end;
end;



//正規化
function NowNormalize2D(const a:TVector2D):TVector2D;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;  DB MM0_mEAX;
    DW    MOVQ_ld;  DB MM2_MM0;
    DW    _3DNow;   DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;   DB MM0_MM0;   DB PFACC;     //2乗和
    DW    _3DNow;   DB MM0_MM0;   DB PFRSQRT;   //これで、1/kがでる
    DW    _3DNow;   DB MM0_MM2;   DB PFMUL;     //元の値と掛け算

    //結果の格納
    DW    MOVQ_st;  DB MM0_mEDX;

    DW    FEMMS;
  end;
end;


//ベクトルの長さをkにする
function NowChangeLength2D(const a:TVector2D; const k:Single):TVector2D;
begin
  asm
    DW    FEMMS;

    mov   ecx,a;
    mov   eax,[k];

    DW    MOVQ_ld;  DB MM0_mECX;
    DW    MOVQ_ld;  DB MM2_MM0;

    DW    _3DNow;   DB MM0_MM0;   DB PFMUL;
    DW    MOVD_ld;  DB MM1_EAX;

    DW    _3DNow;   DB MM0_MM0;   DB PFACC;     //2乗和
    DW    PUNPCKLDQ; DB MM1_MM1;

    DW    _3DNow;   DB MM0_MM0;   DB PFRSQRT;   //これで、1/長さ がでる
    DW    _3DNow;   DB MM0_MM2;   DB PFMUL;     //元の値と掛け算(正規化)
    DW    _3DNow;   DB MM0_MM1;   DB PFMUL;

    //結果の格納
    mov   eax,@result;
    DW    MOVQ_st;  DB MM0_mEAX;

    DW    FEMMS;

  end;
end;


//posからtargetに向いた長さkのベクトルを生成
function NowLookAt2D(const pos:TVector2D; const target:TVector2D; const k:Single):TVector2D;
begin
  asm
    DW    FEMMS;

    mov   eax,[k]
    mov   edx,pos;
    mov   ecx,target;
    DW    MOVQ_ld;    DB MM0_mEDX;
    DW    MOVQ_ld;    DB MM1_mECX;

    DW    _3DNow;     DB MM0_MM1;   DB PFSUBR;  //ターゲットを向いたベクトル

    DW    MOVQ_ld;    DB MM2_MM0;

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    MOVD_ld;    DB MM1_EAX;

    DW    _3DNow;     DB MM0_MM0;   DB PFACC;     //2乗和
    DW    PUNPCKLDQ;  DB MM1_MM1;

    DW    _3DNow;     DB MM0_MM0;   DB PFRSQRT;   //これで、1/長さ がでる
    DW    _3DNow;     DB MM0_MM2;   DB PFMUL;     //元の値と掛け算(正規化)
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;

    //結果の格納
    mov   eax,@result;
    DW    MOVQ_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;
end;


//長さkのランダムなベクトルを作る
function NowRandom2D(const k:Single):TVector2D;
begin
  result:=NowChangeLength2D(Vector2D(Random,Random),k);
end;


/////////////////////////////////////
// 3D計算パッケージ(ベクトル)
/////////////////////////////////////

//足し算
function NowAdd(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVD_ld;    DB MM2_bEAX;  DB 8;

    DW    MOVQ_ld;    DB MM1_mEDX;
    DW    MOVD_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM2_MM3;   DB PFADD;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVD_st;    DB MM2_bECX;  DB 8;

    DW    FEMMS;
  end;
end;

function NowAddHg(const a:THgVector; const b:THgVector):THgVector;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;

    DW    MOVQ_ld;    DB MM1_mEDX;
    DW    MOVQ_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM2_MM3;   DB PFADD;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVQ_st;    DB MM2_bECX;  DB 8;

    DW    FEMMS;
  end;
end;


//引き算
function NowSub(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVD_ld;    DB MM2_bEAX;  DB 8;

    DW    MOVQ_ld;    DB MM1_mEDX;
    DW    MOVD_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM1;   DB PFSUB;
    DW    _3DNow;     DB MM2_MM3;   DB PFSUB;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVD_st;    DB MM2_bECX;  DB 8;

    DW    FEMMS;
  end;
end;

function NowSubHg(const a:THgVector; const b:THgVector):THgVector;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;

    DW    MOVQ_ld;    DB MM1_mEDX;
    DW    MOVQ_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM1;   DB PFSUB;
    DW    _3DNow;     DB MM2_MM3;   DB PFSUB;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVQ_st;    DB MM2_bECX;  DB 8;

    DW    FEMMS;
  end;
end;


//内積
procedure NowDotProduct(var dest:Single; const a:D3DVECTOR; const b:D3DVECTOR);
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEDX;  //a
    DW    MOVQ_ld;    DB MM1_mECX;  //b
    DW    MOVD_ld;    DB MM2_bEDX;  DB 8;   //a.z
    DW    MOVD_ld;    DB MM3_bECX;  DB 8;   //b.z

    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM2_MM3;   DB PFMUL;
    DW    _3DNow;     DB MM2_MM2;   DB PFACC;

    DW    _3DNow;     DB MM0_MM2;   DB PFADD;

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;
end;

//外積…AMDのSDKより引用
function NowCrossProduct(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    DW    movd_ld;    DB mm0_bEDX;  DB 8;       //bz
    DW    movd_ld;    DB mm1_bEAX;  DB 8;       //az
    DW    movd_ld;    DB mm3_bEAX;  DB 4;       //ay
    DW    punpckldq;	DB MM0_MM0;               //b_z,b_z	in	mm0
    DW    _3DNow;     DB MM0_mEAX;  DB pfmul;   //ay*bz,ax*bz
    DW    punpckldq;  DB mm1_mm1;               //az,a_z	in	mm1
    DW    _3DNow;     DB mm1_mEDX;  DB pfmul;		//by*az,bx*az
    DW    movd_ld;    DB mm4_bEDX;  DB 4;     	//by
    DW    movq_ld;    DB mm2_mm0
    DW    _3DNow;     DB mm3_mEDX;  DB pfmul;		//undef,bx*ay
    DW    _3DNow;     DB mm0_MM1;   DB pfsub;		//x,undef
    DW    _3DNow;     DB mm4_mEAX;  DB pfmul;   //undef,ax*by
    DW    _3DNow;     DB mm1_mm2;   DB pfsub;		//undef,y
    DW    psXXimq;    DB mm0_SRLim; DB 32;
    DW    _3DNow;     DB mm4_mm3;   DB pfsub;
    DW    MOVD_st;    DB mm0_mECX;
    DW    MOVD_st;    Db mm1_bECX;  DB 4;
    DW    MOVD_st;    DB mm4_bECX;  DB 8;

    DW    FEMMS;
  end;
end;


//2点の距離
procedure NowDistance(var dest:Single;  const a,b:D3DVECTOR);
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEDX;
    DW    MOVD_ld;    DB MM1_bEDX;  DB 8;
    DW    MOVQ_ld;    DB MM2_mECX;
    DW    MOVD_ld;    DB MM3_bECX;  DB 8;

    DW    _3DNow;     DB MM0_MM2;   DB PFSUB;
    DW    _3DNow;     DB MM1_MM3;   DB PFSUB;
    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;

    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;

    DW    _3DNow;     DB MM1_MM0;   DB PFRSQRT;
    DW    _3Dnow;     DB MM0_MM1;   DB PFMUL;

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;
end;


//原点回りの回転(各軸を左回りに)
function NowRotX(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
begin
  asm
    DW  FEMMS;

    // X' = X
    // Y'=  YcosT + ZsinT
    // Z' = YnsinT + ZcosT    //nsinは-sin
    and   edx,4095;
    shl   edx,3;

    DW    MOVD_ld;    DB MM7_mEAX;            //xを読みこむ = x'
    DW    MOVQ_ld;    DB MM0_bEAX;    DB 4;   //y,zを読み込む

    mov   eax,PNowCosSinT;
    add   eax,edx;
    DW    MOVQ_ld;    DB MM1_MM0;

    DW    _3DNow;     DB MM0_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;     DB PFACC;   //Y'

    mov   eax,PNowNSinCosT;
    add   eax,edx;
    DW    _3DNow;     DB MM1_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;     DB PFACC;   //Z'


    //結果を入れる
    DW    PUNPCKLDQ;  DB MM7_MM0;   //MM7  X' Y'
    DW    MOVQ_st;    DB MM7_mECX;
    DW    MOVD_st;    DB MM1_bECX;    DB 8; // Z'


    DW  FEMMS;
  end;
end;

function NowRotY(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
begin
  asm
    DW  FEMMS;

    // X' = XcosT + ZsinT
    // Y'=  Y
    // Z' = XnsinT + ZcosT    //nsinは-sin
    and   edx,4095;
    shl   edx,3;

    DW    MOVD_ld;    DB MM7_bEAX;    DB 4;   //yを読みこむ = y'
    DW    MOVD_ld;    DB MM0_mEAX;
    DW    MOVD_ld;    DB MM1_bEAX;    DB 8;
    DW    PUNPCKLDQ;  DB MM0_MM1;             //x,zを読み込む

    mov   eax,PNowCosNSinT;
    add   eax,edx;
    DW    MOVQ_ld;    DB MM1_MM0;

    DW    _3DNow;     DB MM0_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;     DB PFACC;   //X'

    mov   eax,PNowSinCosT;
    add   eax,edx;
    DW    _3DNow;     DB MM1_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;     DB PFACC;   //Z'


    //結果を入れる
    DW    PUNPCKLDQ;  DB MM0_MM7;   //MM7  X' Y'
    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVD_st;    DB MM1_bECX;    DB 8;


    DW  FEMMS;
  end;
end;

function NowRotZ(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
begin
  asm
    DW  FEMMS;

    // X' = XcosT + YsinT
    // Y' = XnsinT + YcosT
    // Z' = Z
    and   edx,4095;
    shl   edx,3;

    DW    MOVD_ld;    DB MM7_bEAX;    DB 8;   //zを読みこむ = z'
    DW    MOVQ_ld;    DB MM0_mEAX;            //x,yを読み込む

    mov   eax,PNowCosSinT;
    add   eax,edx;
    DW    MOVQ_ld;    DB MM1_MM0;

    DW    _3DNow;     DB MM0_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;     DB PFACC;   //X'

    mov   eax,PNowNSinCosT;
    add   eax,edx;
    DW    _3DNow;     DB MM1_mEAX;    DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;     DB PFACC;   //Y'


    //結果を入れる
    DW    PUNPCKLDQ;  DB MM0_MM1;   //MM0  X' Y'
    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVD_st;    DB MM7_bECX;    DB 8;


    DW  FEMMS;
  end;
end;

//ベクトルの反転
function NowNeg(const a:D3DVECTOR):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    DW    PXOR;       DB MM0_MM0; //0
    DW    PXOR;       DB MM1_MM1;

    DW    MOVD_ld;    DB MM2_bEAX;  DB 8;
    DW    _3DNow;     DB MM0_mEAX;  DB PFSUB;
    DW    _3DNow;     DB MM1_MM2;   DB PFSUB;

    DW    MOVQ_st;    DB MM0_mEDX;
    DW    MOVD_st;    DB MM1_bEDX;    DB 8;

    DW    FEMMS;
  end;
end;


//正規化
function NowNormalize(const a:D3DVECTOR):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    DW    PXOR;       DB MM1_MM1;
    DW    MOVQ_ld;    DB MM0_mEAX;          //x y
    DW    MOVD_ld;    DB MM1_bEAX;  DB 8;   //z 0

    DW    MOVQ_ld;    DB MM2_MM0;
    DW    MOVQ_ld;    DB MM3_MM1;

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM0_MM0;   DB PFRSQRT;   //長さの逆数

    DW    _3DNow;     DB MM2_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM3_MM0;   DB PFMUL;     //元のベクトルを長さで割る

    DW    MOVQ_st;    DB MM2_mEDX;
    DW    MOVD_st;    DB MM3_bEDX;  DB 8;


    DW    FEMMS;
  end;
end;

//長さを得る
procedure NowLength(var dest:Single; const a:D3DVECTOR);
begin
  asm
    DW    FEMMS;

    DW    PXOR;       DB MM1_MM1;
    DW    MOVQ_ld;    DB MM0_mEDX;          //x y
    DW    MOVD_ld;    DB MM1_bEDX;  DB 8;   //z 0

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM1_MM0;   DB PFRSQRT;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;     //長さ

    DW    MOVD_st;    DB MM0_mEAX;

    DW    FEMMS;
  end;
end;

//スケーリング
function NowScale(const a:D3DVECTOR; const scale:Single):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    mov   eax,a;
    mov   edx,scale;
    mov   ecx,@result;

    DW    MOVQ_ld;    DB MM0_mEAX;          // MM0 = x y
    DW    MOVQ_ld;    DB MM1_bEAX;  DB 8;   // MM1 = z w
    DW    MOVD_ld;    DB MM2_EDX;
    DW    PUNPCKLDQ;  DB MM2_MM2;           // MM2 = scale scale

    DW    _3DNow;     DB MM0_MM2;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM2;   DB PFMUL;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVD_st;    DB MM1_bECX;  DB 8;

    DW    FEMMS;
  end;
end;

//長さを k に
function NowChangeLength(const a:D3DVECTOR; const k:Single):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    mov   eax,a;

    DW    PXOR;       DB MM1_MM1;
    DW    MOVQ_ld;    DB MM0_mEAX;          //x y
    DW    MOVD_ld;    DB MM1_bEAX;  DB 8;   //z 0

    DW    MOVQ_ld;    DB MM2_MM0;
    DW    MOVQ_ld;    DB MM3_MM1;

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM0_MM0;   DB PFRSQRT;   //長さの逆数

    mov   eax,k;
    DW    MOVD_ld;    DB MM5_EAX;
    DW    PUNPCKLDQ;  DB MM5_MM5;   //MM5 = k k
    DW    _3DNow;     DB MM0_MM5;   DB PFMUL;     //長さ * k

    DW    _3DNow;     DB MM2_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM3_MM0;   DB PFMUL;     //元のベクトルを長さ*kで割る


    mov   edx,@result;

    DW    MOVQ_st;    DB MM2_mEDX;
    DW    MOVD_st;    DB MM3_bEDX;  DB 8;

    DW    FEMMS;
  end;
end;

//posからtargetに向いた長さkのベクトルを生成
function NowLookAt(const pos:D3DVECTOR; const target:D3DVECTOR; const k:Single):D3DVECTOR;
begin
  asm
    DW    FEMMS;

    mov   eax,pos;
    mov   edx,target;
    mov   ecx,k;

    DW    MOVQ_ld;    DB MM0_mEAX;          //x y (pos)
    DW    MOVD_ld;    DB MM1_bEAX;  DB 8;   //z 0

    mov   eax,@result;

    DW    MOVQ_ld;    DB MM2_mEDX;          //x y (target)
    DW    MOVD_ld;    DB MM3_bEDX;  DB 8;   //z 0

    DW    _3DNow;     DB MM0_MM2;  DB PFSUBR;
    DW    _3DNow;     DB MM1_MM3;  DB PFSUBR;


    DW    MOVQ_ld;    DB MM2_MM0;
    DW    MOVQ_ld;    DB MM3_MM1;

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM0_MM0;   DB PFRSQRT;   //長さの逆数

    DW    MOVD_ld;    DB MM5_ECX;
    DW    PUNPCKLDQ;  DB MM5_MM5;   //MM5 = k k
    DW    _3DNow;     DB MM0_MM5;   DB PFMUL;     //長さ * k

    DW    _3DNow;     DB MM2_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM3_MM0;   DB PFMUL;     //元のベクトルを長さ*kで割る



    DW    MOVQ_st;    DB MM2_mEAX;
    DW    MOVD_st;    DB MM3_bEAX;  DB 8;

    DW    FEMMS;
  end;
end;


//正規化除算(x,y,z,w) → (x/w, y/w, z/w, 1/w)
function NowViewFrustumToScreen(const a:THgVector):THgVector;
begin
  asm
    DW    FEMMS;
                                                  // L | H

    DW    MOVQ_ld;    DB MM0_mEAX;                // x | y
    DW    MOVQ_ld;    DB MM1_bEAX;  DB  8;        // z | w

    DW    MOVQ_ld;    DB MM2_MM1;
    DW    PUNPCKHDQ;  DB MM2_MM2;
    DW    _3DNow;     DB MM2_MM2;   DB PFRCP;     //1/w | 1/w

    DW    _3DNow;     DB MM0_MM2;   DB PFMUL;     // x/w | y/w
    DW    _3DNow;     DB MM1_MM2;   DB PFMUL;     // z/w | w/w

    DW    PUNPCKLDQ;  DB MM1_MM2;                 // z/w | 1/w

    DW    MOVQ_st;    DB MM0_mEDX;
    DW    MOVQ_st;    DB MM1_bEDX;  DB 8;

    DW    FEMMS;
  end;
end;


//////////////////////////////////////////////
//クォータニオン演算
//////////////////////////////////////////////


//足し算
function NowAddQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_bEAX;  DB 8;
    DW    MOVQ_ld;    DB MM2_mEDX;
    DW    MOVQ_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM2;   DB PFADD;
    DW    _3DNow;     DB MM1_MM3;   DB PFADD;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVQ_st;    DB MM1_bECX;  DB 8;

    DW    FEMMS;
  end;
end;


//引き算
function NowSubQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  asm
    DW    FEMMS;

    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_bEAX;  DB 8;
    DW    MOVQ_ld;    DB MM2_mEDX;
    DW    MOVQ_ld;    DB MM3_bEDX;  DB 8;

    DW    _3DNow;     DB MM0_MM2;   DB PFSUB;
    DW    _3DNow;     DB MM1_MM3;   DB PFSUB;

    DW    MOVQ_st;    DB MM0_mECX;
    DW    MOVQ_st;    DB MM1_bECX;  DB 8;

    DW    FEMMS;
  end;
end;


//乗算
function NowMulQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  asm
    DW    FEMMS;

    //a1a1 a2a2　の格納

    DW    MOVD_ld;    DB MM5_bEAX;  DB 12;
    DW    PUNPCKLDQ;  DB MM5_MM5;               //a1 | a1
    DW    MOVQ_ld;    DB MM3_MM5;
    DW    _3DNow;     DB MM5_mEDX;  DB PFMUL;   //a1 * V2x | a1 *V2y
    DW    _3DNow;     DB MM3_bEDX;  DB 8;      DB PFMUL;    //a1 * V2z | a1 * V2w

    DW    MOVD_ld;    DB MM6_bEDX;  DB 12;
    DW    PUNPCKLDQ;  DB MM6_MM6;               //a2 | a2
    DW    MOVQ_ld;    DB MM4_MM6;
    DW    _3DNow;     DB MM6_mEAX;  DB PFMUL;   //a2 * V1x | a2 *V1y
    DW    _3DNow;     DB MM4_bEAX;  DB 8;      DB PFMUL;    //a2 * V1z | a2 * V1w

    DW    _3DNow;     DB MM6_MM5;   DB PFADD;
    DW    _3DNow;     DB MM4_MM3;   DB PFADD;
    DW    MOVQ_ld;    DB MM5_MM4;



    //外積の計算
                                                //        lo    hi
    DW    MOVQ_ld;    DB MM0_bEAX;  DB 4;       // MM0 = a.y | a.z
    DW    MOVD_ld;    DB MM2_mEDX;
    DW    MOVD_ld;    DB MM1_bEDX;  DB 8;
    DW    PUNPCKLDQ;  DB MM1_MM2;               // MM1 = b.z | b.x
    DW    _3DNow;     DB MM0_MM1;   DB  PFMUL;

    DW    MOVQ_ld;    DB MM2_bEDX;  DB 4        // MM2 = b.y | b.z
    DW    MOVD_ld;    DB MM4_mEAX;
    DW    MOVD_ld;    DB MM3_bEAX;  DB 8;
    DW    PUNPCKLDQ;  DB MM3_MM4;               // MM3 = a.z | b.x
    DW    _3DNow;     DB MM2_MM3;   DB PFMUL;

    DW    _3DNow;     DB MM0_MM2;   DB PFSUB;
    DW    _3DNow;     DB MM0_MM6;   DB PFADD;   //a1V2 + a2V1 を足す
    DW    MOVQ_st;    DB MM0_mECX;              //お先にx,yだけ格納


    DW    MOVD_ld;    DB MM0_mEAX;
    DW    MOVD_ld;    DB MM1_bEDX;  DB 4;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;   // MM0 = a.x * b.y

    DW    MOVD_ld;    DB MM2_bEAX;  DB 4;
    DW    MOVD_ld;    DB MM3_mEDX;
    DW    _3DNow;     DB MM2_MM3;   DB PFMUL;   // MM2 = a.y * b.x

    DW    _3DNow;     DB MM0_MM2;   DB PFSUB;
    DW    _3DNow;     DB MM0_MM5;   DB PFADD;   //a1V2 + a2V1 を足す

    DW    MOVQ_ld;    DB MM7_MM0;               //MM7 = z | ?


    //内積の計算
    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_mEDX;
    DW    _3DNow;     DB MM0_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;

    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;
    DW    MOVD_ld;    DB MM3_bEDX;  DB 8;
    DW    _3DNow;     DB MM2_MM3;   DB PFMUL;
    DW    _3DNow;     DB MM2_MM2;   DB PFACC;

    DW    _3DNow;     DB MM0_MM2;   DB PFADD;   //MM0 = 内積

    DW    MOVD_ld;    DB MM1_bEAX;  DB 12;
    DW    MOVD_ld;    DB MM2_bEDX;  DB 12;
    DW    _3DNow;     DB MM1_MM2;   DB PFMUL;   //a1a2

    DW    _3DNow;     DB MM0_MM1;   DB PFSUBR;  //a1a2 - 内積


    //結果を格納
    DW    PUNPCKLDQ;  DB MM7_MM0;
    DW    MOVQ_st;    DB MM7_bECX;  DB 8;


    DW    FEMMS;
  end;
end;


//内積
procedure NowDotQuat(var dest:Single; const a:TQuaternion; const b:TQuaternion);
asm
  DW    FEMMS;

  DW    MOVQ_ld;    DB MM0_mEDX;  //a.x,y
  DW    MOVQ_ld;    DB MM1_mECX;  //b.x,y
  DW    MOVQ_ld;    DB MM2_bEDX;  DB 8;   //a.z,w
  DW    MOVQ_ld;    DB MM3_bECX;  DB 8;   //b.z,w

  DW    _3DNow;     DB MM0_MM1;   DB PFMUL;
  DW    _3DNow;     DB MM0_MM0;   DB PFACC;
  DW    _3DNow;     DB MM2_MM3;   DB PFMUL;
  DW    _3DNow;     DB MM2_MM2;   DB PFACC;

  DW    _3DNow;     DB MM0_MM2;   DB PFADD;

  DW    MOVD_st;    DB MM0_mEAX;  //dest

  DW    FEMMS;
end;

//ノルム
procedure NowLengthQuat(var dest:Single; const a:TQuaternion);
asm
  DW    FEMMS;

  DW    MOVQ_ld;    DB MM0_mEDX;          //a.x,y
  DW    MOVQ_ld;    DB MM2_bEDX;  DB 8;   //a.z,w

  DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
  DW    _3DNow;     DB MM2_MM2;   DB PFMUL;
  DW    _3DNow;     DB MM0_MM0;   DB PFACC;
  DW    _3DNow;     DB MM2_MM2;   DB PFACC;

  DW    _3DNow;     DB MM0_MM2;   DB PFADD; //ここまでで、ノルムの２乗

  DW    MOVQ_ld;    DB MM1_MM0;               // 一旦退避
  DW    _3DNow;     DB MM0_MM1;   DB PFRSQRT; // 1/SQRT
  DW    _3DNow;     DB MM1_MM0;   DB PFMUL;   //掛けて出来上がり

  DW    MOVD_st;    DB MM1_mEAX;  //dest

  DW    FEMMS;
end;


//正規化
function NowNormalizeQuat(const a:TQuaternion):TQuaternion;
var
  len:Single;
begin
  NowLengthQuat(len, a);

  if len = 0.0 then begin
    result:=Quaternion(1, 0,0,0);
    exit;
  end;

  result.x:=a.X / len;
  result.y:=a.Y / len;
  result.z:=a.Z / len;
  result.w:=a.W / len;

end;



//回転を表すクォータニオンを作る
function  NowQuatFromRotation(const axis:D3DVECTOR; const t:Integer):TQuaternion;
begin
  asm
    DW    FEMMS;

    //q = ( cos T/2 , sinT/2 Vaxis )

    //まず、aを正規化
    DW    MOVQ_ld;    DB MM0_mEAX;          //x y
    DW    MOVD_ld;    DB MM1_bEAX;  DB 8;   //z 0

    DW    MOVQ_ld;    DB MM2_MM0;
    DW    MOVQ_ld;    DB MM3_MM1;

    DW    _3DNow;     DB MM0_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM1_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;
    DW    _3DNow;     DB MM1_MM1;   DB PFACC;
    DW    _3DNow;     DB MM0_MM1;   DB PFADD;
    DW    _3DNow;     DB MM0_MM0;   DB PFRSQRT;   //長さの逆数

    DW    _3DNow;     DB MM2_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM3_MM0;   DB PFMUL;     //元のベクトルを長さで割る

    //MM2 = x y
    //MM3 = z 0


    //テーブルの参照とか
    sar   edx,1;
    mov   eax,PNowCosSinT;
    and   edx,4095;
    shl   edx,3;
    add   eax,edx;

    DW    MOVQ_ld;    DB MM7_mEAX;    //MM7(lo) = w;
    DW    MOVQ_ld;    DB MM6_MM7;
    DW    PUNPCKHDQ;  DB MM6_MM6;     //MM6 = sinT/2

    DW    _3DNow;     DB MM3_MM6;   DB PFMUL;
    DW    PUNPCKLDQ;  DB MM3_MM7;
    DW    _3DNow;     DB MM2_MM6;   DB PFMUL;


    //結果の格納
    DW    MOVQ_st;    DB MM2_mECX;
    DW    MOVQ_st;    DB MM3_bECX;  DB 8;


    DW    FEMMS;
  end;
end;


//正規化済みクォータニオンから行列を作る…ひでぇコード(^^;)
function  NowMatrixFromQuat(const a:TQuaternion):D3DMATRIX;
begin
  asm
    push  ebx;
    push  edi;

    DW    FEMMS;

    //読みこみ  MM0 = x   MM1 = y   MM2 = z   MM3 = w
    DW    MOVQ_ld;    DB MM0_mEAX;
    DW    MOVQ_ld;    DB MM1_MM0;
    DW    PUNPCKLDQ;  DB MM0_MM0;
    DW    PUNPCKHDQ;  DB MM1_MM1;

    DW    MOVQ_ld;    DB MM2_bEAX;   DB 8;
    DW    MOVQ_ld;    DB MM3_MM2;
    DW    PUNPCKLDQ;  DB MM2_MM2;
    DW    PUNPCKHDQ;  DB MM3_MM3;

    mov   eax,$3F800000;    //MM7 = 1.0
    DW    MOVD_ld;    DB MM7_EAX;


    // m11
    DW    MOVQ_ld;    DB MM4_MM1;
    DW    MOVQ_ld;    DB MM5_MM2;
    DW    PUNPCKLDQ;  DB MM4_MM5;   //MM4 = y | z
    DW    _3DNow;     DB MM4_MM4;   DB PFMUL;
    DW    _3DNow;     DB MM4_MM4;   DB PFACC;
    DW    _3DNow;     DB MM4_MM4;   DB PFACC;
    DW    _3DNow;     DB MM4_MM7;   DB PFSUBR;    //MM4 = 1-2(yy+zz)
    //m12
    DW    MOVQ_ld;    DB MM5_MM0;
    DW    MOVQ_ld;    DB MM6_MM1;
    DW    PUNPCKLDQ;  DB MM5_MM2;   //MM5 = x | z
    DW    PUNPCKLDQ;  DB MM6_MM3;   //MM6 = y | w
    DW    _3DNow;     DB MM5_MM6;   DB PFMUL;
    DW    _3Dnow;     DB MM5_MM5;   DB PFACC;
    DW    _3Dnow;     DB MM5_MM5;   DB PFACC;     //MM5 = 2(xy+wz)
    //m11,m12まとめる
    DW    PUNPCKLDQ;  DB MM4_MM5;
    DW    MOVQ_st;    DB MM4_mEDX;


    //m13 2(xz-wy)
    DW    MOVQ_ld;    DB MM4_MM0;
    DW    MOVQ_ld;    DB MM5_MM2;
    DW    PUNPCKLDQ;  DB MM4_MM3;   //MM4 = x | w
    DW    PUNPCKLDQ;  DB MM5_MM1;   //MM5 = z | y
    DW    _3DNow;     DB MM4_MM5;   DB PFMUL;
    DW    MOVQ_ld;    DB MM5_MM4;
    DW    PUNPCKHDQ;  DB MM5_MM5;
    DW    _3DNow;     DB MM4_MM5;   DB PFSUB;   //xz - wy
    DW    _3DNow;     DB MM4_MM4;   DB PFADD;   //2倍
    //m14 = 0
    DW    PXOR;       DB MM5_MM5;
    DW    PUNPCKLDQ;  DB MM4_MM5;
    DW    MOVQ_st;    DB MM4_bEDX;  DB 8;



    //m21 2(xy-wz)
    DW    MOVQ_ld;    DB MM4_MM0;
    DW    MOVQ_ld;    DB MM5_MM1;
    DW    PUNPCKLDQ;  DB MM4_MM3;   //MM4 = x | w
    DW    PUNPCKLDQ;  DB MM5_MM2;   //MM5 = y | z
    DW    _3DNow;     DB MM4_MM5;   DB PFMUL;
    DW    MOVQ_ld;    DB MM5_MM4;
    DW    PUNPCKHDQ;  DB MM5_MM5;
    DW    _3DNow;     DB MM4_MM5;   DB PFSUB;   //xy - wz
    DW    _3DNow;     DB MM4_MM4;   DB PFADD;   //2倍
    //m22 1-2(xx+zz)
    DW    MOVQ_ld;    DB MM5_MM0;
    DW    MOVQ_ld;    DB MM6_MM2;
    DW    PUNPCKLDQ;  DB MM5_MM6;   //MM4 = x | z
    DW    _3DNow;     DB MM5_MM5;   DB PFMUL;
    DW    _3DNow;     DB MM5_MM5;   DB PFACC;
    DW    _3DNow;     DB MM5_MM5;   DB PFACC;
    DW    _3DNow;     DB MM5_MM7;   DB PFSUBR;    //MM4 = 1-2(xx+zz)
    //m21,m22まとめる
    DW    PUNPCKLDQ;  DB MM4_MM5;
    DW    MOVQ_st;    DB MM4_bEDX;  DB 16

    //m23 2(yz+wx)
    DW    MOVQ_ld;    DB MM5_MM1;
    DW    MOVQ_ld;    DB MM6_MM2;
    DW    PUNPCKLDQ;  DB MM5_MM3;   //MM5 = y | w
    DW    PUNPCKLDQ;  DB MM6_MM0;   //MM6 = z | x
    DW    _3DNow;     DB MM5_MM6;   DB PFMUL;
    DW    _3Dnow;     DB MM5_MM5;   DB PFACC;
    DW    _3Dnow;     DB MM5_MM5;   DB PFACC;     //MM5 = 2(yz+wx)
    //m24 = 0
    DW    PXOR;       DB MM4_MM4;
    DW    PUNPCKLDQ;  DB MM5_MM4;
    DW    MOVQ_st;    DB MM5_bEDX;  DB 24;


    //m31 2(xz+wy)
    DW    MOVQ_ld;    DB MM4_MM0;
    DW    MOVQ_ld;    DB MM5_MM2;
    DW    PUNPCKLDQ;  DB MM4_MM3;   //MM4 = x | w
    DW    PUNPCKLDQ;  DB MM5_MM1;   //MM5 = z | y
    DW    _3DNow;     DB MM4_MM5;   DB PFMUL;
    DW    _3Dnow;     DB MM4_MM4;   DB PFACC;
    DW    _3Dnow;     DB MM4_MM4;   DB PFACC;     //MM5 = 2(xz+wy)
    //m32 2(yz-wx)
    DW    MOVQ_ld;    DB MM5_MM1;
    DW    MOVQ_ld;    DB MM6_MM2;
    DW    PUNPCKLDQ;  DB MM5_MM3;   //MM5 = y | w
    DW    PUNPCKLDQ;  DB MM6_MM0;   //MM6 = z | x
    DW    _3DNow;     DB MM5_MM6;   DB PFMUL;
    DW    MOVQ_ld;    DB MM6_MM5;
    DW    PUNPCKHDQ;  DB MM6_MM6;
    DW    _3DNow;     DB MM5_MM6;   DB PFSUB;   //xy - wz
    DW    _3DNow;     DB MM5_MM5;   DB PFADD;   //2倍
    //m31 & m32
    DW    PUNPCKLDQ;  DB MM4_MM5;
    DW    MOVQ_st;    DB MM4_bEDX;  DB 32;

    //m33 1-2(xx+yy)
    DW    MOVQ_ld;    DB MM4_MM0;
    DW    MOVQ_ld;    DB MM5_MM1;
    DW    PUNPCKLDQ;  DB MM4_MM5;   //MM4 = x | y
    DW    _3DNow;     DB MM4_MM4;   DB PFMUL;
    DW    _3DNow;     DB MM4_MM4;   DB PFACC;
    DW    _3DNow;     DB MM4_MM4;   DB PFACC;
    DW    _3DNow;     DB MM4_MM7;   DB PFSUBR;    //MM4 = 1-2(xx+yy)
    //m34 = 0とまとめる
    DW    PXOR;       DB MM5_MM5;
    DW    PUNPCKLDQ;  DB MM4_MM5;
    DW    MOVQ_st;    DB MM4_bEDX;  DB 40;

    //m41,m42 = 0
    DW    MOVQ_st;    DB MM5_bEDX;  DB 48;

    //m43=0 , m44=1;
    DW    PUNPCKLDQ;  DB MM5_MM7;
    DW    MOVQ_st;    DB MM5_bEDX;  DB 56;


    DW    FEMMS;

    pop   edi;
    pop   ebx;
  end;
end;

//axis回りの回転を表す行列を作る(QuadtFromRotationとMatrixFromQuatの合成)
function  NowMatrixFromRotation(const axis:D3DVECTOR; const t:Integer):D3DMATRIX;
begin
  result:=NowMatrixFromQuat(NowQuatFromRotation(axis,t));
end;


//Slerp rate=0.0ならaを100%、 rate=1.0ならbを100% の割合で球面線形補間
function  NowSlerpQuat(const a:TQuaternion; const b:TQuaternion; const rate:Single):TQuaternion;
var
  c,s:Single;     //a,bのなす角のCosとSin
  angle:Single; //a,bのなす角
  ra,rb:Single; //aとbの混合比

begin

  //Sin,Cosの使用が避けられないので、アセンブラ使っても大して高速化できないっしょ。

  NowDotQuat(c, a,b); //Cosθ

  //クォータニオンが正規化されてないっぽいので帰る
  if Abs(c) > 1.0 then begin
    result:=Quaternion(1, 0,0,0);
    exit;
  end;

  //ArcCosで、角度を求める
  angle:=ArcTan(sqrt (1-sqr (c)) /c);

  //角度が違わないなら帰る
  if angle = 0.0 then begin
    result:=a;
    exit;
  end;

  //Sinθを求めて
  s:=Sin(angle);

  //こんな感じで
  ra:=Sin( (1-rate) * angle ) / s;
  rb:=Sin( rate * angle ) / s;

  with result do begin
    x:=a.x*ra + b.x*rb;
    y:=a.y*ra + b.y*rb;
    z:=a.z*ra + b.z*rb;
    w:=a.w*ra + b.w*rb;
  end;

 result:=NowNormalizeQuat(result);
end;






//////////////////////3D演算(マトリクス)

//ベクトルを変換(同次…ジオメトリの変換に)
function NowTransform(const a:THgVector; const m:D3DMATRIX):THgVector;
begin
  asm
    DW    FEMMS;

    DW    movq_ld;    DB mm0_mEAX;		          // ay, ax	in mm0
    DW    movq_ld;    DB mm1_bEAX;  DB 8;		    // aw, az	in mm1
    //
    DW    movq_ld;    DB mm4_mEDX;      		    // m01, m00	in mm4
    DW    punpckhdq;	DB mm2_mm0;		            // ay, undef	in mm2
    //
    DW    movq_ld;       DB mm5_bEDX;  DB 16;	    // m11, m10	in mm5
    DW    punpckldq;  DB mm0_mm0;       		    // ax, ax	in mm2
    //
    DW    movq_ld;    DB mm6_bEDX;  DB 32;      // m21, m20	in mm6
    DW    _3DNow;     DB mm4_mm0;   DB pfmul;   // ax*m01, ax*m00	in mm4
    //
    DW    movq_ld;    DB mm7_bEDX;  DB 48;      // m31, m30	in mm7
    DW    punpckhdq;  DB mm2_mm2;           		// ay, ay	in mm2
    //
    DW    punpckhdq;  DB mm3_mm1;           		// aw, undef	in mm3
    DW    _3DNow;     DB mm5_mm2;   DB pfmul; 	// ay*m11, ay*m10
    //
    DW    punpckldq;  DB mm1_mm1;           		// az, az	in mm3
    DW    _3DNow;     DB mm0_bEDX;  DB 8;   DB pfmul;   	// ax*m03, ax*m02 in mm0
    //
    DW    punpckhdq;  DB mm3_mm3;            		// aw, aw	in mm3
    DW    _3DNow;     DB mm2_bEDX;  DB 24;  DB PFMUL;     // ay*13, ay*m12	in mm2
    //
    DW    _3DNow;     DB mm6_mm1;   DB pfmul; 	// az*m21, az*m20	in mm6
    DW    _3DNow;     DB mm5_mm4;   DB pfadd;
    //
    DW    _3DNow;     DB mm1_bEDX;  DB 40;    DB pfmul    // az*23, az*22	in mm1
    DW    _3DNow;     DB mm2_mm0;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm3;   DB pfmul;   // aw*m31, aw*m30	in mm7
    DW    _3DNow;     DB mm6_mm5;   DB pfadd;
    //
    DW    _3DNow;     DB mm3_bEDX;  DB 56;    DB pfmul;   // aw*m33, aw*m32	in mm3
    DW    _3DNow;     DB mm2_mm1;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm6;   DB pfadd    // ry, rx	in mm7
    DW    _3DNow;     DB mm3_mm2;   DB pfadd		// rw,rz		in mm3
    DW    movq_st;    DB mm7_mECX;
    DW    movq_st;    DB mm3_bECX;  DB 8;

    DW    FEMMS;

  end;
end;

//ベクトルを一気に変換
procedure NowTransformBatch(const src:Pointer; const m:D3DMATRIX; const num:Integer; const span:Integer);
begin
  asm
    push  ebx;

    DW    FEMMS;

    DW    PREFETCH;   DB MM0_bEDX;  DB 0;
    DW    PREFETCH;   DB MM0_bEDX;  DB 8;

    //まじめ計算

    DW    MOVQ_ld;    DB MM0_bEAX;  DB 0;     //MM0 = x
    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;     //MM2 = z
    DW    MOVQ_ld;    DB MM1_MM0;             //MM1 = y
    DW    MOVQ_ld;    DB MM3_MM2              //MM3 = w


    @TransformLoop:

    DW    PREFETCHW;  DB MM1_mEAX;            //この頂点と次の頂点をキャッシュに入れる

    DW    PUNPCKLDQ;  DB MM0_MM0;
    DW    MOVQ_ld;    DB MM4_mEDX;            //mm4 = m11 | m12
    DW    PUNPCKHDQ;  DB MM1_MM1;
    DW    MOVQ_ld;    DB MM5_bEDX;  DB 16;    //mm5 = m21 | m22
    DW    PUNPCKLDQ;  DB MM2_MM2;
    DW    MOVQ_ld;    DB MM6_bEDX;  DB 32     //mm4 = m31 | m32
    DW    PUNPCKHDQ;  DB MM3_MM3;
    DW    MOVQ_ld;    DB MM7_bEDX;  DB 48;    //mm5 = m41 | m42

    DW    _3DNow;     DB MM4_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM5_MM1;   DB PFMUL;
    DW    _3DNow;     DB MM6_MM2;   DB PFMUL;
    DW    _3DNow;     DB MM7_MM3;   DB PFMUL;

    DW    _3DNow;     DB MM4_MM5;   DB PFADD;
    DW    MOVQ_ld;    DB MM5_bEDX;  DB 24 ;   //mm5 = m23 | m24
    DW    _3DNow;     DB MM6_MM7;   DB PFADD;
    DW    MOVQ_ld;    DB MM7_bEDX;  DB 56;    //mm5 = m43 | m44
    DW    _3DNow;     DB MM4_MM6;   DB PFADD;
    DW    MOVQ_ld;    DB MM6_bEDX;  DB 40     //mm4 = m33 | m34

    DW    MOVQ_st;    DB MM4_mEAX;            //x',y'を格納


    add   eax,span;
    DW    MOVQ_ld;    DB MM4_bEDX;  DB 8      //mm4 = m13 | m14


    DW    _3DNow;     DB MM4_MM0;   DB PFMUL;
    DW    MOVQ_ld;    DB MM0_mEAX;            //MM0 = x

    DW    _3DNow;     DB MM5_MM1;   DB PFMUL;
    DW    MOVQ_ld;    DB MM1_MM0;             //MM1 = y

    DW    _3DNow;     DB MM6_MM2;   DB PFMUL;
    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;     //MM2 = z

    DW    _3DNow;     DB MM7_MM3;   DB PFMUL;
    DW    MOVQ_ld;    DB MM3_MM2              //MM3 = w


    DW    _3DNow;     DB MM4_MM5;   DB PFADD;
    DW    _3DNow;     DB MM6_MM7;   DB PFADD;

    DW    _3DNow;     DB MM4_MM6;   DB PFADD;
    DW    MOVQ_st;    DB MM4_bEAX;  DB -8;     //z',w'を格納

    LOOP  @TransformLoop;


    {
    //不真面目ルーチン(w=1で決め打ち)

    DW    MOVD_ld;    DB MM6_bEDX;  DB 8
    DW    PUNPCKLDQ;  DB MM6_bEDX;  DB 24     //MM6 = m13 | m23
    DW    MOVD_ld;    DB MM7_bEDX;  DB 40;
    DW    PUNPCKLDQ;  DB MM7_bEDX;  DB 56;    //MM7 = m33 | m43
    mov   ebx,$3F800000;


    @TransformLoop:

    DW    PREFETCH;   DB MM0_mEAX;

    DW    MOVQ_ld;    DB MM0_mEAX;            //MM0 = x | x
    DW    MOVQ_ld;    DB MM2_bEAX;  DB 8;     //MM2 = z | z
    DW    MOVQ_ld;    DB MM1_MM0;             //MM1 = y | y
    DW    PUNPCKLDQ;  DB MM0_MM0;
    DW    PUNPCKHDQ;  DB MM1_MM1;
    DW    PUNPCKLDQ;  DB MM2_MM2;

    DW    MOVQ_ld;    DB MM3_MM0;
    DW    MOVQ_ld;    DB MM4_MM1;
    DW    MOVQ_ld;    DB MM5_MM2;
    DW    _3DNow;     DB MM3_mEDX;  DB PFMUL;
    DW    _3DNow;     DB MM4_bEDX;  DB 16;    DB PFMUL;
    DW    _3DNow;     DB MM5_bEDX;  DB 32;    DB PFMUL;
    DW    _3DNow;     DB MM3_MM4;   DB PFADD;
    DW    _3DNow;     DB MM3_MM5;   DB PFADD;
    DW    _3DNow;     DB MM3_bEDX;  DB 48;    DB PFADD;
    DW    MOVQ_st;    DB MM3_mEAX;            // x'とy'を格納

    DW    PUNPCKLDQ;  DB MM0_MM1;             //MM0 = x | y
    DW    _3DNow;     DB MM0_MM6;   DB PFMUL;
    DW    MOVD_ld;    DB MM4_EBX;
    DW    PUNPCKLDQ;  DB MM2_MM4;             //MM2 = z | 1

    DW    _3DNow;     DB MM2_MM7;   DB PFMUL;
    DW    _3DNow;     DB MM0_MM2;   DB PFADD;
    DW    _3DNow;     DB MM0_MM0;   DB PFACC;

    DW    PUNPCKLDQ;  DB MM0_MM4;

    DW    MOVQ_st;    DB MM0_bEAX;  DB 8;

    add   eax,16;

    LOOP  @TransformLoop;

    }

    DW    FEMMS;
    pop   ebx;
  end;
end;

//カメラとターゲットの位置から、ビュー行列を作る
//ワールド座標→視野座標
function NowViewMatrix(const from:D3DVECTOR; const at:D3DVECTOR; const world_up:D3DVECTOR; const roll:Integer):D3DMATRIX;
var
  up,right,direction:D3DVECTOR; //頭の中心→頭のてっぺん、頭の中心→右耳、視線の方向
begin
  direction:=NowNormalize(NowSub(at,from));
  right := NowCrossProduct(world_up, direction);
  up:=NowCrossProduct(direction,right);

  right:=NowNormalize(right);
  up:=NowNormalize(up);


  result:=NowIdentityMatrix;
  result._11 := right.x;
  result._21 := right.y;
  result._31 := right.z;
  result._12 := up.x;
  result._22 := up.y;
  result._32 := up.z;
  result._13 := direction.x;
  result._23 := direction.y;
  result._33 := direction.z;

  NowDotProduct(result._41, right, from);
  result._41:=-result._41;
  NowDotProduct(result._42, up, from);
  result._42:=-result._42;
  NowDotProduct(result._43, direction, from);
  result._43:=-result._43;

  result._44:=1;

  if roll <> 0 then begin
    result:=NowCompositeMatrix(NowRotZMatrix(roll),result);
  end;

end;


//姿勢・位置からビュー行列を作る
function NowViewMatixFromOrientation(const from:D3DVECTOR; const dir:D3DVECTOR; const up:D3DVECTOR):D3DMATRIX;
var
  vx,vy,vz:D3DVECTOR;
begin
  vy:=NowNormalize(up);
  vz:=NowNormalize(dir);
  vx:=NowNormalize(NowCrossProduct(up,dir));

  result:=NowIdentityMatrix;
  with result do begin
    _11:=vx.x;    _12:=vy.x;    _13:=vz.x;
    _21:=vx.y;    _22:=vy.y;    _23:=vz.y;
    _31:=vx.z;    _32:=vy.z;    _33:=vz.z;

    NowDotProduct(_41, vx,from);
    _41:=-_41;
    NowDotProduct(_42, vy,from);
    _42:=-_42;
    NowDotProduct(_43, vz,from);
    _43:=-_43;
  end;
end;


//透視射影行列(視野座標→除算前正規化座標)を作る
function NowProjectFrustum(const halfWidth:Single; const halfHeight:Single; const nearZ:Single; const farZ:Single):D3DMATRIX;
begin
  ZeroMemory(@result,sizeof(D3DMATRIX));

  with result do begin
    _11:=nearZ * halfHeight * 2;

    _22:=-_11;

    _31:=halfWidth;
    _32:=halfHeight;
    _33:=farZ / (farZ-nearZ);
    _34:=1.0;

    _43:=_33 * (-nearZ);
  end;
end;

function NowRotXMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  Move(NowIdentityMatrix,result,sizeof(D3DMATRIX));
  with result do begin
    _22:=NowCosT[t2];   _23:=NowSinT[t2];
    _32:=-NowSinT[t2];  _33:=NowCosT[t2];
  end;
end;

function NowRotYMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  Move(NowIdentityMatrix,result,sizeof(D3DMATRIX));
  with result do begin
    _11:=NowCosT[t2]; _13:=-NowSinT[t2];
    _31:=NowSinT[t2]; _33:=NowCosT[t2];   _34:=0;
  end;
end;

function NowRotZMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  Move(NowIdentityMatrix,result,sizeof(D3DMATRIX));
  with result do begin
    _11:=NowCosT[t2];   _12:=NowSinT[t2];
    _21:=-NowSinT[t2];  _22:=NowCosT[t2];
  end;
end;


//スケーリング行列
function NowScaleMatrix(const x,y,z:Single):D3DMATRIX;
begin
  with result do begin
    _11:=x;   _12:=0; _13:=0; _14:=0;
    _21:=0;   _22:=y; _23:=0; _24:=0;
    _31:=0;   _32:=0; _33:=z; _34:=0;
    _41:=0;   _42:=0; _43:=0; _44:=1;
  end;
end;

//平行移動行列
function NowTranslateMatrix(const x,y,z:Single):D3DMATRIX;
begin
  with result do begin
    _11:=0;   _12:=0; _13:=0; _14:=0;
    _21:=0;   _22:=0; _23:=0; _24:=0;
    _31:=0;   _32:=0; _33:=0; _34:=0;
    _41:=x;   _42:=y; _43:=z; _44:=1;
  end;
end;


//逆行列
function NowInvMatrix(const m:D3DMATRIX):D3DMATRIX;
begin
  with result do begin
    _11:=m._11;   _12:=m._21;   _13:=m._31;   _14:=0;
    _21:=m._12;   _22:=m._22;   _23:=m._32;   _24:=0;
    _31:=m._13;   _32:=m._23;   _33:=m._33;   _34:=0;

    _41:= - (m._11*m._41 + m._12*m._42 + m._13*m._43);
    _42:= - (m._21*m._41 + m._22*m._42 + m._23*m._43);
    _43:= - (m._31*m._41 + m._32*m._42 + m._33*m._43);
    _44:= 1;
  end;
end;

//転置行列
function NowTMatrix(const m:D3DMATRIX):D3DMATRIX;
begin
  with result do begin
    _11:=m._11;   _12:=m._21;   _13:=m._31;   _14:=m._41;
    _21:=m._12;   _22:=m._22;   _23:=m._32;   _24:=m._42;
    _31:=m._13;   _32:=m._23;   _33:=m._33;   _34:=m._43;
    _41:=m._14;   _42:=m._24;   _43:=m._34;   _44:=m._44;
  end;
end;


//回転部分だけ抜き出し
function NowExtractRotation(const m:D3DMATRIX):D3DMATRIX;
begin
  result:=NowIdentityMatrix;
  with result do begin
    _11:=m._11;   _12:=m._12;   _13:=m._13;
    _21:=m._21;   _22:=m._22;   _23:=m._23;
    _31:=m._31;   _32:=m._32;   _33:=m._33;
  end;
end;

//平行移動部分だけ抜き出し
function NowExtractTranslation(const m:D3DMATRIX):D3DMATRIX;
begin
  result:=NowIdentityMatrix;
  with result do begin
    _41:=m._41;   _42:=m._42;   _43:=m._43;
  end;
end;

//マトリクスの合成
function NowCompositeMatrix(const m:D3DMATRIX; const n:D3DMATRIX):D3DMATRIX;
begin
  asm
    push  ebx;

    DW    FEMMS;

    mov   ebx,4;


    @LOOP_1:;

    DW    PREFETCH;   DB MM0_bEAX;  DB 16;

    DW    movq_ld;    DB mm0_mEAX;		          // ay, ax	in mm0
    DW    movq_ld;    DB mm1_bEAX;  DB 8;		    // aw, az	in mm1
    //
    DW    movq_ld;    DB mm4_mEDX;      		    // m01, m00	in mm4
    DW    punpckhdq;	DB mm2_mm0;		            // ay, undef	in mm2
    //
    DW    movq_ld;       DB mm5_bEDX;  DB 16;	    // m11, m10	in mm5
    DW    punpckldq;  DB mm0_mm0;       		    // ax, ax	in mm2
    //
    DW    movq_ld;    DB mm6_bEDX;  DB 32;      // m21, m20	in mm6
    DW    _3DNow;     DB mm4_mm0;   DB pfmul;   // ax*m01, ax*m00	in mm4
    //
    DW    movq_ld;    DB mm7_bEDX;  DB 48;      // m31, m30	in mm7
    DW    punpckhdq;  DB mm2_mm2;           		// ay, ay	in mm2
    //
    DW    punpckhdq;  DB mm3_mm1;           		// aw, undef	in mm3
    DW    _3DNow;     DB mm5_mm2;   DB pfmul; 	// ay*m11, ay*m10
    //
    DW    punpckldq;  DB mm1_mm1;           		// az, az	in mm3
    DW    _3DNow;     DB mm0_bEDX;  DB 8;   DB pfmul;   	// ax*m03, ax*m02 in mm0
    //
    DW    punpckhdq;  DB mm3_mm3;            		// aw, aw	in mm3
    DW    _3DNow;     DB mm2_bEDX;  DB 24;  DB PFMUL;     // ay*13, ay*m12	in mm2
    //
    DW    _3DNow;     DB mm6_mm1;   DB pfmul; 	// az*m21, az*m20	in mm6
    DW    _3DNow;     DB mm5_mm4;   DB pfadd;
    //
    DW    _3DNow;     DB mm1_bEDX;  DB 40;    DB pfmul    // az*23, az*22	in mm1
    DW    _3DNow;     DB mm2_mm0;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm3;   DB pfmul;   // aw*m31, aw*m30	in mm7
    DW    _3DNow;     DB mm6_mm5;   DB pfadd;
    //
    DW    _3DNow;     DB mm3_bEDX;  DB 56;    DB pfmul;   // aw*m33, aw*m32	in mm3
    DW    _3DNow;     DB mm2_mm1;   DB pfadd;
    //
    DW    _3DNow;     DB mm7_mm6;   DB pfadd    // ry, rx	in mm7
    DW    _3DNow;     DB mm3_mm2;   DB pfadd		// rw,rz		in mm3
    DW    movq_st;    DB mm7_mECX;
    DW    movq_st;    DB mm3_bECX;  DB 8;


    {
    DW    MOVQ_ld;    DB MM0_mEAX;            //MM0 = x
    DW    MOVQ_ld;    DB MM2_bEAX;    DB 8;   //MM2 = z
    DW    MOVQ_ld;    DB MM1_MM0;             //MM1 = y
    DW    MOVQ_ld;    DB MM3_MM2              //MM3 = w
    DW    PUNPCKLDQ;  DB MM0_MM0;
    DW    PUNPCKHDQ;  DB MM1_MM1;
    DW    PUNPCKLDQ;  DB MM2_MM2;
    DW    PUNPCKHDQ;  DB MM3_MM3;

    DW    MOVQ_ld;    DB MM4_mEDX;            //mm4 = m11 | m12
    DW    MOVQ_ld;    DB MM5_bEDX;  DB 16;    //mm5 = m21 | m22
    DW    _3DNow;     DB MM4_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM5_MM1;   DB PFMUL;

    DW    MOVQ_ld;    DB MM6_bEDX;  DB 32     //mm4 = m31 | m32
    DW    MOVQ_ld;    DB MM7_bEDX;  DB 48;    //mm5 = m41 | m42
    DW    _3DNow;     DB MM6_MM2;   DB PFMUL;
    DW    _3DNow;     DB MM7_MM3;   DB PFMUL;

    DW    _3DNow;     DB MM4_MM5;   DB PFADD;
    DW    _3DNow;     DB MM6_MM7;   DB PFADD;
    DW    _3DNow;     DB MM4_MM6;   DB PFADD;

    DW    MOVQ_st;    DB MM4_mECX;            //x',y'を格納


    DW    MOVQ_ld;    DB MM4_bEDX;  DB 8      //mm4 = m13 | m14
    DW    MOVQ_ld;    DB MM5_bEDX;  DB 24 ;   //mm5 = m23 | m24
    DW    _3DNow;     DB MM4_MM0;   DB PFMUL;
    DW    _3DNow;     DB MM5_MM1;   DB PFMUL;

    DW    MOVQ_ld;    DB MM6_bEDX;  DB 40     //mm4 = m33 | m34
    DW    MOVQ_ld;    DB MM7_bEDX;  DB 56;    //mm5 = m43 | m44
    DW    _3DNow;     DB MM6_MM2;   DB PFMUL;
    DW    _3DNow;     DB MM7_MM3;   DB PFMUL;

    DW    _3DNow;     DB MM4_MM5;   DB PFADD;
    DW    _3DNow;     DB MM6_MM7;   DB PFADD;
    DW    _3DNow;     DB MM4_MM6;   DB PFADD;

    DW    MOVQ_st;    DB MM4_bECX;  DB 8;     //z',w'を格納
    }

    add   eax,16;
    add   ecx,16;

    dec   ebx;
    jnz   @LOOP_1;


    DW    FEMMS;
    pop   ebx;
  end;
end;


{$ELSE}

///////////////////////////////////////////////////////////////////////////////
// x87バージョン
///////////////////////////////////////////////////////////////////////////////


//////////////////////変換

function  NowItoF2D(const a:TPoint):TVector2D;
begin
  result.X:=a.X;
  result.Y:=a.Y;
end;

function  NowFtoI2D(const a:TVector2D):TPoint;
begin
  result.X:=Trunc(a.X);
  result.Y:=Trunc(a.Y);
end;

function  NowRound2D(const a:TVector2D):TPoint;
begin
  result.X:=Round(a.X);
  result.Y:=Round(a.Y);
end;

function  NowLVToTLV(const lv:D3DLVERTEX; const transMat:D3DMATRIX):D3DTLVERTEX;
var
  hg:THgVector;  //頂点座標
begin
  Move(lv,hg,Sizeof(D3DVERTEX));
  hg.W:=1;

  hg:=NowViewFrustumToScreen(NowTransform(hg,transMat));
  Move(hg,result,sizeof(THgVector));
  Move(lv.color,result.color,sizeof(D3DTLVERTEX) - sizeof(THgVector));

end;


procedure NowLVToTLVBatch(src:LPD3DLVERTEX; dest:LPD3DTLVERTEX; const transMat:D3DMATRIX; count:Integer);
var
  i:Integer;
begin
  for i:=0 to count-1 do begin
    dest^:=NowLVToTLV(src^,transMat);
    Inc(dest);
    Inc(src);
  end;
end;


//////////////////////1D演算

//スプライン補間(4点を与えられて、中間2点のブレンド比を与えて補間
procedure NowInterpolate(var dest:Single; const p1,p2,p3,p4:Single; const rate:Single);
var
  ir:Single;      //1-rate
  r2,r3:Single;   //rate^2　, rate^3
begin
  ir:=1-rate;
  r2:=rate*rate;
  r3:=r2*rate;

  dest:= ( (p1*ir*ir*ir) + p2*(3*r3-6*r2+4) + p3*(-3*(r3-r2-rate)+1) + p4*r3)  / 6.0;
end;

//線形補間(rateは２点のブレンド比で0〜1、1に近いほどp2が濃くなる。
procedure NowLerp(var dest:Single; const p1,p2:Single; const rate:Single);
begin
  dest:=rate*p2 + (1.0-rate)*p1;
end;

function SQR(x:Single):Single;
begin
  result:=x*x;
end;


//////////////////////2D演算

//ベクトルの足し算
function NowAdd2D(const a:TVector2D; const b:TVector2D):TVector2D;
begin
  result.X:=a.X + b.X;
  result.Y:=a.Y + b.Y;
end;

//ベクトルの引き算
function NowSub2D(const a:TVector2D; const b:TVector2D):TVector2D;
begin
  result.X:=a.X - b.X;
  result.Y:=a.Y - b.Y;
end;

//内積
procedure NowDotProduct2D(var dest:Single; const a:TVector2D; const b:TVector2D);
begin
  dest:=a.X * b.X + a.Y * b.Y;
end;

//2点の距離
procedure NowDistance2D(var dest:Single; const a,b:TVector2D);
begin
  dest:=sqrt(SQR(a.X-b.X) + SQR(a.Y-b.Y));
end;

//長さを算出
procedure NowLength2D(var dest:Single; const a:TVector2D);
begin
  dest:=sqrt(SQR(a.X) + SQR(a.Y));
end;

//ベクトルの向きを4096度系で
procedure NowVecToAngle2D(var dest:Integer; const a:TVector2D);
var
  v:TVector2D;
  sg:Integer;   //象限
  hi,lo,mid:Integer;  //2分探索用
begin
  //まず、ベクトルをノーマライズする
  v:=NowNormalize2D(a);

  //象限はどれ？
  if (v.y > 0) then begin
    if v.x > 0 then
      sg:=1
    else begin
      sg:=2;
      v.x:=-v.x;
    end;
  end else if (v.y < 0) then begin
    if v.x >= 0 then
      sg:=4
    else begin
      sg:=3;
      v.x:=-v.x;
    end;
  end else begin
    if v.x >= 0 then
      sg:=1
    else begin
      sg:=3;
      v.x:=-v.x;
    end;
  end;


  hi:=1023;
  lo:=0;
  mid:=511;
  //Cosテーブル内を2分探索し、角度を求める
  while hi > lo do begin
    if NowCosT[mid] > v.x then
      lo:=mid+1
    else
      hi:=mid;
    mid:=(hi+lo) Shr 1;
  end;

  //象限に応じて、結果を加工
  Case sg of
    1: dest:=mid;
    2: dest:=2047-mid;
    3: dest:=2048+mid;
    4: dest:=4095-mid;
  end;

end;


//回転(原点を右回りにangleだけ)
function NowRot2D(const a:TVector2D; const angle:Integer):TVector2D;
var
  t:Integer;
begin
  t:=angle and 4095;
  result.X:=a.X * NowCosT[t] - a.Y * NowSinT[t];
  result.Y:=a.X * NowSinT[t] + a.Y * NowCosT[t];
end;

//正規化(長さを1に)
function NowNormalize2D(const a:TVector2D):TVector2D;
var
  len:Single;
begin
  NowLength2D(len,a);
  if len = 0 then begin
    result:=Vector2D(0,0);
    Exit;
  end;

  result.X:=a.X / len;
  result.Y:=a.Y / len;
end;

//スケーリング
function NowScale2D(const a:TVector2D; const scale:Single):TVector2D;
begin
  result.X:=a.X * scale;
  result.Y:=a.Y * scale;
end;

//ベクトルの長さをkにする
function NowChangeLength2D(const a:TVector2D; const k:Single):TVector2D;
var
  len:Single;
begin
  NowLength2D(len,a);
  if len = 0 then begin
    result:=Vector2D(0,0);
    Exit;
  end;

  result.X:=a.X * k / len;
  result.Y:=a.Y * k / len;
end;

//posからtargetに向いた長さkのベクトルを生成
function NowLookAt2D(const pos:TVector2D; const target:TVector2D; const k:Single):TVector2D;
var
  sub:TVector2D;
  len:Single;
begin
  sub:=NowSub2D(target,pos);
  NowLength2D(len,sub);
  if len = 0 then begin
    result:=Vector2D(0,0);
    Exit;
  end;

  result.X:=sub.X * k / len;
  result.Y:=sub.Y * k / len;
end;

//長さkのランダムなベクトルを作る
function NowRandom2D(const k:Single):TVector2D;
begin
  result:=NowChangeLength2D(Vector2D(Random-0.5,Random-0.5),k);
end;



//////////////////////3D演算(ベクトル)

//足し算
function NowAdd(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  result.X:=a.X + b.X;
  result.Y:=a.Y + b.Y;
  result.Z:=a.Z + b.Z;
end;

function NowAddHg(const a:THgVector; const b:THgVector):THgVector;
begin
  result.X:=a.X + b.X;
  result.Y:=a.Y + b.Y;
  result.Z:=a.Z + b.Z;
  result.W:=a.W + b.W;
end;


//引き算
function NowSub(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  result.X:=a.X - b.X;
  result.Y:=a.Y - b.Y;
  result.Z:=a.Z - b.Z;
end;

function NowSubHg(const a:THgVector; const b:THgVector):THgVector;
begin
  result.X:=a.X - b.X;
  result.Y:=a.Y - b.Y;
  result.Z:=a.Z - b.Z;
  result.W:=a.W - b.W;
end;


//内積
procedure NowDotProduct(var dest:Single; const a:D3DVECTOR; const b:D3DVECTOR);
begin
  dest:=a.X*b.X + a.Y*b.Y + a.Z*b.Z;
end;

//外積
function NowCrossProduct(const a:D3DVECTOR; const b:D3DVECTOR):D3DVECTOR;
begin
  result.x := a.y*b.z - a.z*b.y;
  result.y := a.z*b.x - a.x*b.z;
  result.z := a.x*b.y - a.y*b.x;
end;


//2点の距離
procedure NowDistance(var dest:Single;  const a,b:D3DVECTOR);
begin
  dest:=sqrt(SQR(a.X-b.X) + SQR(a.Y-b.Y) + SQR(a.Z-b.Z));
end;

//原点回りの回転(各軸を左回りに)
function NowRotX(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
var
  r:Integer;
begin
  r:=t and 4095;

  result.X:=a.X;
  result.Y:=a.Y*NowCosT[r] + a.Z*NowSinT[r];
  result.Z:=-a.Y*NowSinT[r] + a.Z*NowCosT[r];
end;

function NowRotY(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
var
  r:Integer;
begin
  r:=t and 4095;

  result.X:=a.X*NowCosT[r] - a.Z*NowSinT[r];
  result.Y:=a.Y;
  result.Z:=a.X*NowSinT[r] + a.Z*NowCosT[r];
end;

function NowRotZ(const a:D3DVECTOR; const t:Integer):D3DVECTOR;
var
  r:Integer;
begin
  r:=t and 4095;

  result.X:=a.X*NowCosT[r] + a.Y*NowSinT[r];
  result.Y:=-a.X*NowSinT[r] + a.Y*NowCosT[r];
  result.Z:=a.Z;
end;

//ベクトルの反転
function NowNeg(const a:D3DVECTOR):D3DVECTOR;
begin
  result.X:=-a.X;
  result.Y:=-a.Y;
  result.Z:=-a.Z;
end;

//正規化
function NowNormalize(const a:D3DVECTOR):D3DVECTOR;
var
  len:Single;
begin
  NowLength(len,a);
  if len = 0 then begin
    result:=Vector(0,0,0);
    exit;
  end;

  result.X:=a.X / len;
  result.Y:=a.Y / len;
  result.Z:=a.Z / len;
end;

//長さを得る
procedure NowLength(var dest:Single; const a:D3DVECTOR);
begin
  dest:=sqrt(SQR(a.X) + SQR(a.Y) + SQR(a.Z));
end;

//スケーリング
function NowScale(const a:D3DVECTOR; const scale:Single):D3DVECTOR;
begin
  result.X:=a.X * scale;
  result.Y:=a.Y * scale;
  result.Z:=a.Z * scale;
end;

//長さを k に
function NowChangeLength(const a:D3DVECTOR; const k:Single):D3DVECTOR;
var
  len:Single;
begin
  NowLength(len,a);
  if len = 0 then begin
    result:=Vector(0,0,0);
    exit;
  end;

  result.X:=a.X * k / len;
  result.Y:=a.Y * k / len;
  result.Z:=a.Z * k / len;
end;

//posからtargetに向いた長さkのベクトルを生成
function NowLookAt(const pos:D3DVECTOR; const target:D3DVECTOR; const k:Single):D3DVECTOR;
var
  sub:D3DVECTOR;
  len:Single;
begin
  sub:=NowSub(target,pos);
  NowLength(len,sub);
  if len = 0 then begin
    result:=Vector(0,0,0);
    exit;
  end;

  result.X:=sub.X * k / len;
  result.Y:=sub.Y * k / len;
  result.Z:=sub.Z * k / len;
end;


//ViewFrustum(x,y,z,w)→TLVertex座標(x/w,y/w,z/w,1/w)
function NowViewFrustumToScreen(const a:THgVector):THgVector;
begin
  with result do begin
    if a.W <> 0.0 then begin
      W:=1.0 / a.W;
      X:=a.X * W;
      Y:=a.Y * W;
      Z:=a.Z * W;
    end;
  end;
end;


//////////////////////3D演算(クォータニオン)

//足し算
function NowAddQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  result.X:=a.X + b.X;
  result.Y:=a.Y + b.Y;
  result.Z:=a.Z + b.Z;
  result.W:=a.W + b.W;
end;

//引き算
function NowSubQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  result.X:=a.X - b.X;
  result.Y:=a.Y - b.Y;
  result.Z:=a.Z - b.Z;
  result.W:=a.W - b.W;
end;

//乗算
function NowMulQuat(const a:TQuaternion; const b:TQuaternion):TQuaternion;
begin
  result.X:=a.W*b.X + a.X*b.W + a.Y*b.Z - a.Z*b.Y;
  result.Y:=a.W*b.Y + b.W*a.Y + a.Z*b.X - a.X*b.Z;
  result.Z:=a.W*b.Z + b.W*a.Z + a.X*b.Y - a.Y*b.X;
  result.W:=a.W*b.W - a.X*b.X - a.Y*b.Y - a.Z*b.Z;
end;

//内積
procedure NowDotQuat(var dest:Single; const a:TQuaternion; const b:TQuaternion);
begin
  dest:=a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z;
end;

//ノルム
procedure NowLengthQuat(var dest:Single; const a:TQuaternion);
begin
  dest:=sqrt(a.w*a.w + a.x*a.x + a.y*a.y + a.z*a.z);
end;

//正規化
function NowNormalizeQuat(const a:TQuaternion):TQuaternion;
var
  len:Single;
begin
  NowLengthQuat(len, a);

  if len = 0.0 then begin
    result:=Quaternion(1, 0,0,0);
    exit;
  end;

  result.x:=a.X / len;
  result.y:=a.Y / len;
  result.z:=a.Z / len;
  result.w:=a.W / len;

end;


//回転を表すクォータニオンを作る
function  NowQuatFromRotation(const axis:D3DVECTOR; const t:Integer):TQuaternion;
var
  r:Integer;
  a:D3DVECTOR;
begin
  r:=(t div 2) And 4095;

  a:=NowNormalize(axis);
  result.X:=a.X * NowSinT[r];
  result.Y:=a.Y * NowSinT[r];
  result.Z:=a.Z * NowSinT[r];
  result.W:=NowCosT[r];
end;

//クォータニオンから行列を作る
function  NowMatrixFromQuat(const a:TQuaternion):D3DMATRIX;
begin
  result._11:=1.0-2.0*(a.y*a.y+a.z*a.z);
  result._12:=2.0*(a.x*a.y+a.w*a.z);
  result._13:=2.0*(a.x*a.z-a.w*a.y);
  result._14:=0;

  result._21:=2.0*(a.x*a.y-a.w*a.z);
  result._22:=1.0-2.0*(a.x*a.x+a.z*a.z);
  result._23:=2.0*(a.y*a.z+a.w*a.x);
  result._24:=0;

  result._31:=2.0*(a.x*a.z+a.w*a.y);
  result._32:=2.0*(a.y*a.z-a.w*a.x);
  result._33:=1.0-2.0*(a.x*a.x+a.y*a.y);
  result._34:=0;

  result._41:=0;
  result._42:=0;
  result._43:=0;
  result._44:=1;
end;

//axis回りの回転を表す行列を作る(QuadtFromRotationとMatrixFromQuatの合成)
function  NowMatrixFromRotation(const axis:D3DVECTOR; const t:Integer):D3DMATRIX;
begin
  result:=NowMatrixFromQuat(NowQuatFromRotation(axis,t));
end;


//Slerp rate=0.0ならaを100%、 rate=1.0ならbを100% の割合で球面線形補間
function  NowSlerpQuat(const a:TQuaternion; const b:TQuaternion; const rate:Single):TQuaternion;
var
  c,s:Single;     //a,bのなす角のCosとSin
  angle:Single; //a,bのなす角
  ra,rb:Single; //aとbの混合比

begin

  NowDotQuat(c, a,b); //Cosθ

  //クォータニオンが正規化されてないっぽいので帰る
  if Abs(c) > 1.0 then begin
    result:=Quaternion(1, 0,0,0);
    exit;
  end;

  //ArcCosで、角度を求める
  angle:=ArcTan(sqrt (1-sqr (c)) /c);

  //角度が違わないなら帰る
  if angle = 0.0 then begin
    result:=a;
    exit;
  end;

  //Sinθを求めて
  s:=Sin(angle);

  //こんな感じで
  ra:=Sin( (1-rate) * angle ) / s;
  rb:=Sin( rate * angle ) / s;

  with result do begin
    x:=a.x*ra + b.x*rb;
    y:=a.y*ra + b.y*rb;
    z:=a.z*ra + b.z*rb;
    w:=a.w*ra + b.w*rb;
  end;

 result:=NowNormalizeQuat(result);

end;


//////////////////////3D演算(マトリクス)

//ベクトルを変換
function NowTransform(const a:THgVector; const m:D3DMATRIX):THgVector;
begin
  result.X:=a.X*m._11 + a.Y*m._21 + a.Z*m._31 + a.W*m._41;
  result.Y:=a.X*m._12 + a.Y*m._22 + a.Z*m._32 + a.W*m._42;
  result.Z:=a.X*m._13 + a.Y*m._23 + a.Z*m._33 + a.W*m._43;
  result.W:=a.X*m._14 + a.Y*m._24 + a.Z*m._34 + a.W*m._44;
end;

//一気にベクトルを変換
procedure NowTransformBatch(const src:Pointer; const m:D3DMATRIX; const num:Integer; const span:Integer);
var
  i:Integer;
  a:THgVector;
  pSrc:PHgVector;
begin
  pSrc:=src;

  for i:=1 to num do begin
    a:=pSrc^;
    pSrc^.X:=a.X*m._11 + a.Y*m._21 + a.Z*m._31 + a.W*m._41;
    pSrc^.Y:=a.X*m._12 + a.Y*m._22 + a.Z*m._32 + a.W*m._42;
    pSrc^.Z:=a.X*m._13 + a.Y*m._23 + a.Z*m._33 + a.W*m._43;
    pSrc^.W:=a.X*m._14 + a.Y*m._24 + a.Z*m._34 + a.W*m._44;
    Inc(PBYTE(pSrc),span);
  end;
end;

//カメラとターゲットの位置から、ビュー行列を作る
function NowViewMatrix(const from:D3DVECTOR; const at:D3DVECTOR; const world_up:D3DVECTOR; const roll:Integer):D3DMATRIX;
var
  up,right,direction:D3DVECTOR; //頭の中心→頭のてっぺん、頭の中心→右耳、視線の方向
begin
  direction:=NowNormalize(NowSub(at,from));
  right := NowCrossProduct(world_up, direction);
  up:=NowCrossProduct(direction,right);

  right:=NowNormalize(right);
  up:=NowNormalize(up);


  result:=NowIdentityMatrix;
  result._11 := right.x;
  result._21 := right.y;
  result._31 := right.z;
  result._12 := up.x;
  result._22 := up.y;
  result._32 := up.z;
  result._13 := direction.x;
  result._23 := direction.y;
  result._33 := direction.z;

  NowDotProduct(result._41, right, from);
  result._41:=-result._41;
  NowDotProduct(result._42, up, from);
  result._42:=-result._42;
  NowDotProduct(result._43, direction, from);
  result._43:=-result._43;

  if roll <> 0 then begin
    result:=NowCompositeMatrix(NowRotZMatrix(roll),result);
  end;

end;


//姿勢・位置からビュー行列を作る
function NowViewMatixFromOrientation(const from:D3DVECTOR; const dir:D3DVECTOR; const up:D3DVECTOR):D3DMATRIX;
var
  vx,vy,vz:D3DVECTOR;
begin
  vx:=NowNormalize(NowCrossProduct(up,dir));
  vy:=NowNormalize(up);
  vz:=NowNormalize(dir);

  result:=NowIdentityMatrix;
  with result do begin
    _11:=vx.x;    _12:=vy.x;    _13:=vz.x;
    _21:=vx.y;    _22:=vy.y;    _23:=vz.y;
    _31:=vx.z;    _32:=vy.z;    _33:=vz.z;
    _41:=-from.x; _42:=-from.y; _43:=-from.z;
  end;
end;


//透視射影行列(視野座標→除算前正規化座標)を作る
function NowProjectFrustum(const halfWidth:Single; const halfHeight:Single; const nearZ:Single; const farZ:Single):D3DMATRIX;
begin
  ZeroMemory(@result,sizeof(D3DMATRIX));

  with result do begin
    _11:=(nearZ+1) * halfHeight;

    _22:=-_11;

    _31:=halfWidth;
    _32:=halfHeight;
    _33:=farZ / (farZ-nearZ);
    _34:=1.0;

    _43:=_33 * (-nearZ);
  end;
end;


function NowRotXMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  with result do begin
    _11:=1; _12:=0;             _13:=0;           _14:=0;
    _21:=0; _22:=NowCosT[t2];   _23:=NowSinT[t2]; _24:=0;
    _31:=0; _32:=-NowSinT[t2];  _33:=NowCosT[t2]; _34:=0;
    _41:=0; _42:=0;             _43:=0;           _44:=1;
  end;
end;

function NowRotYMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  with result do begin
    _11:=NowCosT[t2]; _12:=0; _13:=-NowSinT[t2];  _14:=0;
    _21:=0;           _22:=1; _23:=0;             _24:=0;
    _31:=NowSinT[t2]; _32:=0; _33:=NowCosT[t2];   _34:=0;
    _41:=0;           _42:=0; _43:=0;             _44:=1;
  end;
end;

function NowRotZMatrix(const t:Integer):D3DMATRIX;
var
  t2:Integer;
begin
  t2:=t And 4095;

  with result do begin
    _11:=NowCosT[t2];   _12:=NowSinT[t2]; _13:=0; _14:=0;
    _21:=-NowSinT[t2];  _22:=NowCosT[t2]; _23:=0; _24:=0;
    _31:=0;             _32:=0;           _33:=1; _34:=0;
    _41:=0;             _42:=0;           _43:=0; _44:=1;
  end;
end;

//スケーリング行列
function NowScaleMatrix(const x,y,z:Single):D3DMATRIX;
begin
  with result do begin
    _11:=x;   _12:=0; _13:=0; _14:=0;
    _21:=0;   _22:=y; _23:=0; _24:=0;
    _31:=0;   _32:=0; _33:=z; _34:=0;
    _41:=0;   _42:=0; _43:=0; _44:=1;
  end;
end;

//平行移動行列
function NowTranslateMatrix(const x,y,z:Single):D3DMATRIX;
begin
  with result do begin
    _11:=0;   _12:=0; _13:=0; _14:=0;
    _21:=0;   _22:=0; _23:=0; _24:=0;
    _31:=0;   _32:=0; _33:=0; _34:=0;
    _41:=x;   _42:=y; _43:=z; _44:=1;
  end;
end;


//逆行列(変換行列用の、手抜き計算)
function NowInvMatrix(const m:D3DMATRIX):D3DMATRIX;
begin
  with result do begin
    _11:=m._11;   _12:=m._21;   _13:=m._31;   _14:=0;
    _21:=m._12;   _22:=m._22;   _23:=m._32;   _24:=0;
    _31:=m._13;   _32:=m._23;   _33:=m._33;   _34:=0;

    _41:= - (m._11*m._41 + m._12*m._42 + m._13*m._43);
    _42:= - (m._21*m._41 + m._22*m._42 + m._23*m._43);
    _43:= - (m._31*m._41 + m._32*m._42 + m._33*m._43);
    _44:= 1;
  end;
end;

//転置行列
function NowTMatrix(const m:D3DMATRIX):D3DMATRIX;
begin
  with result do begin
    _11:=m._11;   _12:=m._21;   _13:=m._31;   _14:=m._41;
    _21:=m._12;   _22:=m._22;   _23:=m._32;   _24:=m._42;
    _31:=m._13;   _32:=m._23;   _33:=m._33;   _34:=m._43;
    _41:=m._14;   _42:=m._24;   _43:=m._34;   _44:=m._44;
  end;
end;

//回転部分だけ抜き出し
function NowExtractRotation(const m:D3DMATRIX):D3DMATRIX;
begin
  with result do begin
    _11:=m._11;   _12:=m._12;   _13:=m._13;   _14:=0;
    _21:=m._21;   _22:=m._22;   _23:=m._23;   _24:=0;
    _31:=m._31;   _32:=m._32;   _33:=m._33;   _34:=0;
    _41:=0;       _42:=0;       _43:=0;       _44:=1;
  end;
end;

//平行移動部分だけ抜き出し
function NowExtractTranslation(const m:D3DMATRIX):D3DMATRIX;
begin
  result:=NowIdentityMatrix;
  with result do begin
    _41:=m._41;   _42:=m._42;   _43:=m._43;
  end;
end;


//マトリクスの合成
function NowCompositeMatrix(const m:D3DMATRIX; const n:D3DMATRIX):D3DMATRIX;
begin

  result._11:= m._11*n._11 + m._12*n._21 + m._13*n._31 + m._14*n._41;
  result._12:= m._11*n._12 + m._12*n._22 + m._13*n._32 + m._14*n._42;
  result._13:= m._11*n._13 + m._12*n._23 + m._13*n._33 + m._14*n._43;
  result._14:= m._11*n._14 + m._12*n._24 + m._13*n._34 + m._14*n._44;

  result._21:= m._21*n._11 + m._22*n._21 + m._23*n._31 + m._24*n._41;
  result._22:= m._21*n._12 + m._22*n._22 + m._23*n._32 + m._24*n._42;
  result._23:= m._21*n._13 + m._22*n._23 + m._23*n._33 + m._24*n._43;
  result._24:= m._21*n._14 + m._22*n._24 + m._23*n._34 + m._24*n._44;

  result._31:= m._31*n._11 + m._32*n._21 + m._33*n._31 + m._34*n._41;
  result._32:= m._31*n._12 + m._32*n._22 + m._33*n._32 + m._34*n._42;
  result._33:= m._31*n._13 + m._32*n._23 + m._33*n._33 + m._34*n._43;
  result._34:= m._31*n._14 + m._32*n._24 + m._33*n._34 + m._34*n._44;

  result._41:= m._41*n._11 + m._42*n._21 + m._43*n._31 + m._44*n._41;
  result._42:= m._41*n._12 + m._42*n._22 + m._43*n._32 + m._44*n._42;
  result._43:= m._41*n._13 + m._42*n._23 + m._43*n._33 + m._44*n._43;
  result._44:= m._41*n._14 + m._42*n._24 + m._43*n._34 + m._44*n._44;

end;


{$ENDIF}





initialization

//なぜか一部の環境では、ここが呼ばれないので、自主的に呼び出すべし
//NowInit;

end.
