unit DX3DWin;

{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, SysUtils, Forms, Dialogs, Classes, Controls, StdCtrls, Buttons, ComCtrls,
  dddd, ddraw, d3d, d3dcaps, d3dtypes, s_mathpack,ExtCtrls,Math,Graphics,
  _DX3D_Rain;

// 全体パラメータ
const SeaWaveMax=256;

// ワイヤーパラメータ
const WireMax=48;
const WirePartMax=32;

// ウェーブパラメータ
const WaveMax=48;
const WaveHisMax=48;

// フライパラメータ
const FlyMax=48;
const FlyHisMax=127;

// プールパラメータ
const PoolPlateMax=64;

// ボックスパラメータ
const BoxChMax=8;
const BoxNoteMax=16;
const BoxNoteMul=4;
const Boxpx=0.8;
const Boxpy=0.8;
const Boxpz=0.8;

type
  WaveVertex=record
    pos:D3DVECTOR;
    n:D3DVECTOR;
    col:dword;
  end;
  TFlyCamera=record
    LocateIndex,TargetIndex:integer; // 目指すポイントのインデックス
  end;
  TFly=record
    Loc:D3DVECTOR;   // 現在位置
    Speed:D3DVECTOR; // 慣性
    Grav:D3DVECTOR;  // 重力場
  end;
  TPoolPlate=record
    _x,_z:single;
    _tu,_tv:single;
  end;
  TPoolWave=record
    y:array[0..PoolPlateMax,0..PoolPlateMax] of single;
  end;

type
  TDX3D = class(TForm)
    DDraw: TDDDD;
    MouseTimer: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MouseTimerTimer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
    procedure SeaWaveTexCreate;
    procedure SeaWaveTexFree;
    procedure DDVisFlip;
    procedure DDVisClear(ClearMode:integer);
    procedure DDVisWire;
    procedure DDVisWave;
    procedure DDVisFly;
    procedure DDVisPoolInit;
    procedure DDVisPoolFree;
    procedure DDVisPool;
    procedure DDVisPoolCalculateWave;
    procedure DDVisPoolRaiseWave(cx,cz:integer;Height:single);
    procedure DDVisBoxInit;
    procedure DDVisBoxFree;
    procedure DDVisBox;
    procedure DDVisRainInit;
    procedure DDVisRainFree;
    procedure DDVisRain;
  public
    { Public 宣言 }
    MouseFlag:boolean;
    mf:boolean;
    mx,my:integer;
    SeaWaveTexInitializedFlag:boolean;
    // 全体パラメータ
    c1cnt,c2cnt:single;
    c1,c2:dword;
    c1r,c1g,c1b,c2r,c2g,c2b:byte;
    FullScreen:boolean;
    Rot:single;
    RotAuto,RotAutoBackup:boolean;
    SeaWaveTex:array[0..SeaWaveMax] of TDDDDTexture;
    SeaWaveCnt:integer;
    // ワイヤーパラメータ
    WireWave:single;
    WireArc:array[0..WireMax,0..WirePartMax] of single;
    // ウェーブパラメータ
    Wave:array[0..WaveMax,0..WaveHisMax] of single;
    WaveColor:array[0..WaveMax,0..WaveHisMax] of dword;
    // フライパラメータ
    FlyCamera:TFlyCamera;
    Fly:array[0..FlyMax] of TFly;
    FlyHisLoc:array[0..FlyMax,0..FlyHisMax] of D3DVECTOR;
    // プールパラメータ
    PoolPlate:array[0..PoolPlateMax,0..PoolPlateMax] of TPoolPlate;
    Poolwave1,Poolwave2,Poolwave3:TPoolWave;
    PoolVsIdx:Array[0..PoolPlateMax*PoolPlateMax*3] of word;
    PoolArgCnt:word;
    // ボックスパラメータ
    BoxOneVs:array[0..36] of D3DVERTEX;
    BoxOneVsCnt:integer;
    BoxHeight:array[0..BoxChMax,0..BoxNoteMax*BoxNoteMul] of single;
    // レイン
    Rain:TRain;

    procedure FreeMemory;
    procedure ChangePosition;
    procedure SetVisible(Visible:boolean);
    procedure DDVisParamInit;
    procedure DDVis;
  end;

var
  DX3D: TDX3D;

implementation

uses MainWin,
     _PicTools,_m_MathPack, _Images, _Vis_const, _MDXWinINI,_WinPosConst,_Vis;

{$R *.dfm}

procedure TDX3D.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Shift=[ssLeft] then begin
    RotAutoBackup:=RotAuto;
    RotAuto:=False;

    mf:=True;
    mx:=x;
    my:=y;
  end;
end;

procedure TDX3D.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  RotAuto:=not RotAutoBackup;

  mf:=False;
  mx:=x;
  my:=y;

//  FullScreen:=not FullScreen;

  Main.SetFocus;
end;

procedure TDX3D.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if MouseFlag=True then begin
    MouseFlag:=False;
    ShowCursor(False);
  end;

  if mf=True then begin
    Rot:=Rot+(mx-x)/100;
    mx:=x;
    my:=y;
  end;
end;

procedure TDX3D.FormActivate(Sender: TObject);
begin
  if Main.Visible=True then begin
//    Main.SetFocus;
    MouseTimerTimer(Sender);
  end;
end;

procedure TDX3D.FormDeactivate(Sender: TObject);
begin
  MouseTimerTimer(Sender);
end;

procedure TDX3D.FormCreate(Sender: TObject);
begin
  SeaWaveTexInitializedFlag:=False;
  MouseFlag:=True;

  RotAuto:=VisINI.Effect3DRotAuto;
  Rot:=VisINI.Effect3DRot/1000;
  FullScreen:=VisINI.Effect3DFullScreen;

  Rain:=nil;

  mf:=False;
  mx:=0;
  my:=0;
end;

procedure TDX3D.FreeMemory;
begin
  DDVisPoolFree;
  DDVisBoxFree;
  DDVisRainFree;

  SeaWaveTexFree;
end;

procedure TDX3D.MouseTimerTimer(Sender: TObject);
var
  NowCursor:TPoint;
begin
  if MouseFlag=False then begin
    GetCursorPos(NowCursor);
    with NowCursor do begin
      dec(x,DX3D.Left);
      dec(y,DX3D.Top);
      if ((x<0) or (DX3D.Width<x) or (y<0) or (DX3D.Height<y)) then begin
        MouseFlag:=True;
        ShowCursor(True);
      end;
    end;
  end;
end;

procedure TDX3D.ChangePosition;
begin
  DX3D.Left:=Main.Left+NotePos.Left;
  DX3D.Top:=Main.Top+NotePos.Top;
  DX3D.Width:=NotePos.Width;
  DX3D.Height:=NotePos.Height;
end;

procedure TDX3D.SetVisible(Visible:boolean);
begin
  DX3D.Color:=$000000;
  DX3D.Visible:=Visible;
end;

procedure TDX3D.DDVisParamInit;
var
  mat:D3DMATRIX;
  viewParam:D3DVIEWPORT7;	//ビューポートを示す情報
  Zn,Zf:Single;           //近・遠クリッピング面までの距離
  q:Single;               //クリッピング面の距離で計算される係数
  mtrl:D3DMATERIAL7;      //マテリアルについての情報を格納する構造体
  light0:D3DLIGHT7;        //光源に関する情報を格納する構造体
  cnt1,cnt2:integer;
begin
  NowInit; // 演算パッケージの初期化

  //ビューポートの特性を指定する
  with viewParam do begin
    dwX:=0;                                //レンダリングが施される左上座標
    dwY:=0;
    dwWidth:=NotePos.Width;       //レンダリングが施される範囲
    dwHeight:=NotePos.Height;
    dvMinZ:=0;					 //Zバッファの有効範囲
    dvMaxZ:=1.0;
  end;
  DDraw.D3DDevice.SetViewport(@viewParam);

  //投影行列 … 画角 = 90度 クリッピング面 (近,遠) = (1.0, 5000.0)
  Zn := 1.0;
  Zf := 5000.0;
  q := Zf / (Zf - Zn);
  with mat do begin
    _11:=1.0; _12:=0;         _13:=0;     _14:=0; //Cot(90/2 deg.) = 1.0
    _21:=0;   _22:=1.0;       _23:=0;     _24:=0; //Cot(90/2 deg.) = 1.0
    _31:=0;   _32:=0;         _33:=q;     _34:=1;
    _41:=0;   _42:=0;         _43:=-q*Zn; _44:=0;
  end;
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_PROJECTION, @mat);

  DDVisClear(D3DCLEAR_TARGET+D3DCLEAR_ZBUFFER);

  //マテリアル
  ZeroMemory(@mtrl, sizeof(mtrl));
  with mtrl do begin
    dcvAmbient:=MakeColorValue(1.0, 0.3, 0.3, 0.3);
    dcvDiffuse:=MakeColorValue(1.0, 0.3, 0.3, 0.3);
    dcvSpecular:=MakeColorValue(1.0, 0.4, 0.4, 0.4);
    dcvEmissive:=MakeColorValue(1.0, 0.0, 0.0, 0.0);
    dvPower:=5.0;
  end;
  DDraw.D3DDevice.SetMaterial(@mtrl);

  //光源…それぞれのパラメータと、マテリアルに指定された値の積が画面に出ます
  ZeroMemory(@light0, Sizeof(light0));
  with light0 do begin
    dcvAmbient:=MakeColorValue(1.0, 1.0, 1.0, 1.0);
    dcvDiffuse:=MakeColorValue(1.0, 1.0, 1.0, 1.0);
    dcvSpecular:=MakeColorValue(1.0, 1.0, 1.0, 1.0);
    dltType:=D3DLIGHT_DIRECTIONAL;
    dvDirection:=NowNormalizeVector(MakeVector(0.0, 0.0, 1.0));
    dvRange:=10000; //適当に、遠くへ
  end;
  //Direct3Dに渡す
  DDraw.D3DDevice.SetLight(0, @light0);  //0番の光源としてセット
  DDraw.D3DDevice.LightEnable(0,True);  //0番の光源をEnableにする。

  with DDraw.D3DDevice do begin
    //レンダリングステートの設定
    SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(False));
    SetRenderState( D3DRENDERSTATE_ZENABLE, Integer(True) );
    SetRenderState( D3DRENDERSTATE_ZWRITEENABLE,Integer(True));
    SetRenderState( D3DRENDERSTATE_COLORVERTEX, Integer(True) );
    SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(False) );
    SetRenderState( D3DRENDERSTATE_SPECULARMATERIALSOURCE, Integer(D3DMCS_COLOR2));
    SetRenderState( D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, Integer(D3DMCS_COLOR1));
    SetRenderState( D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, Integer(D3DMCS_MATERIAL));
    SetRenderState( D3DRENDERSTATE_AMBIENTMATERIALSOURCE, Integer(D3DMCS_MATERIAL));
    SetRenderState( D3DRENDERSTATE_DITHERENABLE, Integer(True));
    SetRenderState( D3DRENDERSTATE_SHADEMODE, Integer(D3DSHADE_GOURAUD));
    SetRenderState( D3DRENDERSTATE_NORMALIZENORMALS, Integer(False) );
    SetRenderState(D3DRENDERSTATE_CULLMODE, Integer(D3DCULL_CCW));

    SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, Integer(False) );
    SetRenderState( D3DRENDERSTATE_SRCBLEND, Integer(D3DBLEND_SRCALPHA) );
    SetRenderState( D3DRENDERSTATE_DESTBLEND, Integer(D3DBLEND_INVSRCALPHA) );

    SetTexture(0, nil);
    SetTextureStageState(0, D3DTSS_COLORARG1, Integer(D3DTA_TEXTURE));
    SetTextureStageState(0, D3DTSS_COLORARG2, Integer(D3DTA_DIFFUSE));
    SetTextureStageState(0, D3DTSS_COLOROP, Integer(D3DTOP_MODULATE));
    SetTextureStageState(0, D3DTSS_ALPHAARG1, Integer(D3DTA_TEXTURE));
    SetTextureStageState(0, D3DTSS_ALPHAARG2, Integer(D3DTA_DIFFUSE));
    SetTextureStageState(0, D3DTSS_ALPHAOP, Integer(D3DTOP_MODULATE));

    SetTextureStageState(0,D3DTSS_MAGFILTER,Integer(D3DTFG_LINEAR));
    SetTextureStageState(0,D3DTSS_MINFILTER,Integer(D3DTFN_LINEAR));

    if VisINI.VisualMode=VisualModePool then begin
      SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
      SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
    end;

    if VisINI.VisualMode=VisualModeBox then begin
      SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
      SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
      // 光源設定
      light0.dvDirection:=NowNormalizeVector(MakeVector(1.0, -1.0, 1.0));
      SetLight(0, @light0);
      // 材質設定
      ZeroMemory(@mtrl, sizeof(mtrl));
      with mtrl do begin
        dcvAmbient:=MakeColorValue(1.0, 0.1, 0.1, 0.2);
        dcvDiffuse:=MakeColorValue(1.0, 0.5, 0.5, 0.9);
        dcvSpecular:=MakeColorValue(1.0, 0.8, 0.8, 0.8);
        dcvEmissive:=MakeColorValue(1.0, 0.0, 0.0, 0.0);
        dvPower:=5.0;
      end;
      SetMaterial(@mtrl);
      SetRenderState(D3DRENDERSTATE_FOGENABLE,Integer(True));
      SetRenderState(D3DRENDERSTATE_FOGCOLOR,Integer($000000));
      SetRenderState(D3DRENDERSTATE_FOGTABLEMODE,Integer(D3DFOG_LINEAR));
      SetRenderState(D3DRENDERSTATE_FOGSTART,Integer(D3DF2DW(16.0)));
      SetRenderState(D3DRENDERSTATE_FOGEND,Integer(D3DF2DW(32.0)));
      SetRenderState(D3DRENDERSTATE_FOGDENSITY,Integer(D3DF2DW(0.0)));
    end;

    if VisINI.VisualMode=VisualModeRain then begin
      SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
      SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
      // 光源設定
      light0.dvDirection:=NowNormalizeVector(MakeVector(0.0, -1.0, 0.0));
      SetLight(0, @light0);
      // 材質設定
      ZeroMemory(@mtrl, sizeof(mtrl));
      with mtrl do begin
        dcvAmbient:=MakeColorValue(1.0, 0.1, 0.1, 0.2);
        dcvDiffuse:=MakeColorValue(0.5, 0.5, 0.5, 0.9);
        dcvSpecular:=MakeColorValue(1.0, 1.0, 1.0, 1.0);
        dcvEmissive:=MakeColorValue(1.0, 0.0, 0.0, 0.0);
        dvPower:=1.0;
      end;
      SetMaterial(@mtrl);
      SetRenderState(D3DRENDERSTATE_FOGENABLE,Integer(True));
      SetRenderState(D3DRENDERSTATE_FOGCOLOR,Integer($000000));
      SetRenderState(D3DRENDERSTATE_FOGTABLEMODE,Integer(D3DFOG_LINEAR));
      SetRenderState(D3DRENDERSTATE_FOGSTART,Integer(D3DF2DW(256.0)));
      SetRenderState(D3DRENDERSTATE_FOGEND,Integer(D3DF2DW(512.0)));
      SetRenderState(D3DRENDERSTATE_FOGDENSITY,Integer(D3DF2DW(0.0)));
    end;
  end;

  // 全体パラメータ初期化
  c1cnt:=random($ff);
  c2cnt:=random($ff);

  // ワイヤーパラメータ初期化
  WireWave:=0;
  for cnt1:=0 to WireMax do begin
    for cnt2:=0 to WirePartMax do begin
      WireArc[cnt1,cnt2]:=(random(2000)-1000)/1000;
    end;
  end;

  // ウェーブパラメータ初期化
  for cnt1:=0 to WaveMax do begin
    for cnt2:=0 to WaveHisMax do begin
      Wave[cnt1,cnt2]:=0;
      WaveColor[cnt1,cnt2]:=0;
    end;
  end;

  // フライパラメータ初期化
  FlyCamera.LocateIndex:=1;

  for cnt1:=0 to FlyMax do begin
    with Fly[cnt1] do begin
      Loc:=MakeVectorPos(0,0,0);
      Speed:=MakeVectorPos(0,0,0);
      Grav:=MakeVectorPos(0,0,0);
    end;
    for cnt2:=0 to FlyHisMax do begin
      FlyHisLoc[cnt1,cnt2]:=Fly[cnt1].Loc;
    end;
  end;

  // プールパラメータ初期化
  DDVisPoolInit;
  if VisINI.VisualMode=VisualModePool then SeaWaveTexCreate;

  // ボックスパラメータ初期化
  DDVisBoxInit;

  // レインパラメータ初期化
  if VisINI.VisualMode=VisualModeRain then begin
    DDVisRainInit;
    SeaWaveTexFree;
  end;
end;

procedure TDX3D.SeaWaveTexCreate;
var
  tc,x,y:integer;
  idx1,idx2:integer;
  Tex0bm,Tex1bm,Tex2bm:TBitmap;
  TexDC:HDC;
  Tex0p,Tex1p,Tex2p:PByteArray;
begin
  // 一時待避用テクスチャメモリ作成
  Tex0bm:=TBitmap.Create;
  with Tex0bm do begin
    PixelFormat:=pf24bit;
    Width:=128;
    Height:=128;
  end;

  //テクスチャ読み込み
  Tex1bm:=TBitmap.Create;
  LoadBitmapFromQDA('MDXWin.qda','SeaWave1.bmp',Tex1bm);
  Tex2bm:=TBitmap.Create;
  LoadBitmapFromQDA('MDXWin.qda','SeaWave2.bmp',Tex2bm);

  //テクスチャ作成
  for tc:=0 to (SeaWaveMax-1) do begin
    if (tc mod 16)=0 then begin
      Main.InfomationVisible('VisualEffect [SeaWaveTexture] Make... ('+IntToStr(tc)+'/'+IntToStr(SeaWaveMax)+')');
    end;
    for y:=0 to 128-1 do begin
      Tex0p:=Tex0bm.Scanline[y];
      Tex1p:=Tex1bm.Scanline[(y-tc+128) and $7f];
      Tex2p:=Tex2bm.Scanline[(y+tc) and $7f];
      for x:=0 to (128*3)-1 do begin
        idx1:=(x+(tc*3)) mod (128*3);
        idx2:=(x+((tc+128) and $7f)*3) mod (128*3);
        Tex0p[x]:=(word(Tex1p[idx1]*160)+word(Tex2p[idx2]*96)) div 256;
      end;
    end;
    if SeaWaveTex[tc]=nil then SeaWaveTex[tc]:=TDDDDTexture.Create(DDraw, 128,128, 0, '');
    TexDC:=SeaWaveTex[tc].GetDC;
    BitBlt(TexDC,0,0,128,128,Tex0bm.Canvas.Handle,0,0,SRCCOPY);
    SeaWaveTex[tc].ReleaseDC;
  end;

  Tex0bm.Free;
  Tex1bm.Free;
  Tex2bm.Free;

  Main.InfomationVisible('VisualEffect [SeaWaveTexture] Initialized.');

  SeaWaveCnt:=0;

  SeaWaveTexInitializedFlag:=True;
end;

procedure TDX3D.SeaWaveTexFree;
var
  tc:integer;
begin
  for tc:=0 to (SeaWaveMax-1) do begin
    if SeaWaveTex[tc]<>nil then SeaWaveTex[tc].Free;
  end;
end;

procedure TDX3D.DDVisFlip;
var
  ddsd:DDSURFACEDESC2;
  sr:TRect;       //転送元矩形
  dr:TRect;       //転送先矩形
  p:TPoint;
  fx:DDBltFx;
begin
  ZeroMemory(@ddsd,sizeof(ddsd));
  ddsd.dwSize := sizeof(ddsd);
  DDraw.BackBuffer.Surface.GetSurfaceDesc(@ddsd);

  //転送元(バックバッファ全体)・転送先(クライアントエリア)・クリップ枠(画面全体)の計算
  with sr do begin
    Top := 0;
    Left := 0;
    Bottom := ddsd.dwHeight;
    Right := ddsd.dwWidth;
  end;

  //クライアント領域全体が、転送先
  if FullScreen=True then begin
    with Screen do
      dr:=Bounds(Left,Top,Width,Height);
    end else begin
    with NotePos do
      dr:=Bounds(Left,Top,Width,Height);
  end;
  p:=Main.ClientToScreen(Point(0,0));
  with dr do begin
    Inc(Left,p.X);
    Inc(Right,p.X);
    Inc(Top,p.Y);
    Inc(Bottom,p.Y);
  end;

  if DDraw.VsyncAtWindowed then
    DDraw.DDraw.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);

  ZeroMemory(@fx,sizeof(fx));
  fx.dwSize:=Sizeof(DDBltFx);

  DDraw.FrontBuffer.Surface.Blt(@dr,DDraw.BackBuffer.Surface,@sr,0,@fx);
end;

procedure TDX3D.DDVis;
var
  mat:D3DMATRIX;
  xs,xc:Single;     //回転用、サイン・コサインの値
  TLVs:Array[0..3] of D3DTLVERTEX; //ブラーの座標
  ScreenRect:TRect;
  procedure DrawPlate(ax,ay:integer);
  begin
    asm finit; end;
    TLVs[0]:=MakeTLVertex( 0, 0, 0.5,0.2, $40000060,$00000000, 0.0,0.0);
    TLVs[1]:=MakeTLVertex(ax, 0, 0.5,0.2, $40000040,$00000000, 1.0,0.0);
    TLVs[2]:=MakeTLVertex( 0,ay, 0.5,0.2, $40000040,$00000000, 0.0,1.0);
    TLVs[3]:=MakeTLVertex(ax,ay, 0.5,0.2, $40000020,$00000000, 1.0,1.0);
    asm finit; end;
    DDraw.D3DDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DFVF_TLVERTEX,@TLVs,4, 0);
    asm finit; end;
  end;
begin
  c1cnt:=c1cnt+0.7;
  if c1cnt>=255 then c1cnt:=0;
  c2cnt:=c2cnt-0.8;
  if c2cnt<=0 then c2cnt:=255;
  c1:=Images.HSVMapBM.Canvas.Pixels[0,trunc(c1cnt)];
  c2:=Images.HSVMapBM.Canvas.Pixels[0,trunc(c2cnt)];
  c1r:=c1 div $10000;
  c1g:=c1 div $100 mod $100;
  c1b:=c1 mod $100;
  c2r:=c2 div $10000;
  c2g:=c2 div $100 mod $100;
  c2b:=c2 mod $100;

  if RotAuto=True then Rot:=Rot+0.01;

  inc(SeaWaveCnt);
  if SeaWaveCnt>=SeaWaveMax then SeaWaveCnt:=0;

  //ビュー行列 … カメラは Z = -5の位置 x軸周りを回転
  xs:=Sin(Rot/1.8);
  xc:=Cos(Rot/1.8);
  with mat do begin
    _11:=1; _12:=0;  _13:= 0;  _14:=0;
    _21:=0; _22:=xc; _23:= -xs;  _24:=0;
    _31:=0; _32:=xs;  _33:= xc;  _34:=0;
    _41:=0; _42:=0;   _43:=5;   _44:=1;
  end;
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

  asm finit; end;
  DDraw.D3DDevice.BeginScene;
  asm finit; end;

  ScreenRect:=Rect(0,0,255,255);

  case Main.DDBlurMode of
    DDBlurModeCopy: begin
      DDVisClear(D3DCLEAR_TARGET+D3DCLEAR_ZBUFFER);
    end;
    DDBlurModeReduction: begin
      asm finit; end;
      DDraw.D3DDevice.SetTexture(0, nil);
      asm finit; end;
      DDVisClear(D3DCLEAR_ZBUFFER);
      asm finit; end;
      with DDraw.D3DDevice do begin
        SetRenderState( D3DRENDERSTATE_ZENABLE, Integer(False) );
        SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,Integer(False));
        SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, Integer(True) );
        SetRenderState( D3DRENDERSTATE_SRCBLEND, Integer(D3DBLEND_SRCALPHA) );
        SetRenderState( D3DRENDERSTATE_DESTBLEND, Integer(D3DBLEND_INVSRCALPHA) );
        DrawPlate(NotePos.Width,NotePos.Height);
        SetRenderState( D3DRENDERSTATE_ZENABLE, Integer(True) );
        SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,Integer(True));
        SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, Integer(False) );
      end;
    end;
    DDBlurModeShade: begin
      // not implimented.
    end;
  end;

  case VisINI.VisualMode of
    VisualModeWire: DDVisWire;
    VisualModeWave: DDVisWave;
    VisualModeFly:  DDVisFly;
    VisualModePool: DDVisPool;
    VisualModeBox:  DDVisBox;
    VisualModeRain: DDVisRain;
  end;

  asm finit; end;
  DDraw.D3DDevice.EndScene;
  asm finit; end;
  DDVisFlip;
end;

procedure TDX3D.DDVisClear(ClearMode:integer);
var
  clearRect:D3DRect;
begin
  with clearRect do begin
    x1:=0;
    y1:=0;
    x2:=DDraw.InitialScreenWidth;
    y2:=DDraw.InitialScreenHeight;
  end;
  asm finit; end;
  DDraw.D3DDevice.Clear(1,@clearRect,ClearMode, $FF000000, 1.0, 0);
end;

// -----------------------
// ----------------------- DX3D.Wire Effect
// -----------------------

procedure TDX3D.DDVisWire;
var
  mat:D3DMATRIX;
  ys,yc:Single;     //回転用、サイン・コサインの値
  Vs:Array[0..1280] of D3DLVertex; //ポリゴンの座標
  CM1,CM2:single; // 色混合率
  cr,cg,cb:byte;
  LineColor:dword;
  Alpha:byte;

  Cnt,PartCnt:integer;
  CurrentArc:single;
  x,y,z,ax,ay:single;
begin
  WireWave:=WireWave+0.01;

  for Cnt:=0 to WireMax do begin
    WireArc[Cnt][0]:=WireArc[Cnt][0]*0+(Vis.PSetVisual.SpeAna[Cnt].Delay/$ff*PI)-sin(Rot*PI);
  end;

  for cnt:=0 to WireMax do begin
    //ワールド行列の変更、y軸回りに回転
    ys:=Sin((cnt/WireMax)*PI*2+Rot/1.4);
    yc:=Cos((cnt/WireMax)*PI*2+Rot/1.4);
    with mat do begin
      _11:=yc; _12:=0;  _13:=ys;  _14:=0;
      _21:=0;  _22:=1;  _23:= 0;   _24:=0;
      _31:=-ys; _32:=0;  _33:=yc;  _34:=0;
      _41:=0;  _42:=(Cnt/WireMax-0.5)*4;  _43:= 0;   _44:=1;
    end;
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);

    CM1:=Cnt/WireMax;
    CM2:=1.0-CM1;
    cr:=trunc(c1r*CM1+c2r*CM2);
    cg:=trunc(c1g*CM1+c2g*CM2);
    cb:=trunc(c1b*CM1+c2b*CM2);
    LineColor:=cr*$10000+cg*$100+cb;

    x:=0;
    y:=0;
    z:=1;
    Vs[0]:=MakeLVertex(x,y,z,  LineColor,0, 0,0);
    for PartCnt:=1 to WirePartMax do begin
      CurrentArc:=WireArc[Cnt][PartCnt];
      ax:=sin(CurrentArc+PI/2);
      ay:=cos(CurrentArc+PI/2);
      x:=x+ax*0.2;
      y:=y+ay*0.2;
      if PartCnt<8 then begin
        Alpha:=PartCnt*$ff div 8;
        end else begin
        if PartCnt>(WirePartMax-8) then begin
          Alpha:=(WirePartMax-PartCnt)*$ff div 8;
          end else begin
          Alpha:=$ff;
        end;
      end;
      Vs[PartCnt]:=MakeLVertex(x,y,z, LineColor+(Alpha shl 24),0, 0,0);
      WireArc[Cnt][PartCnt]:=(WireArc[Cnt][PartCnt-1]-CurrentArc)*(0.4+(PartCnt/WirePartMax*0.4))+CurrentArc;
    end;
    asm finit; end;
    DDraw.D3DDevice.DrawPrimitive(D3DPT_LINESTRIP,D3DFVF_LVERTEX,@Vs,WirePartMax+1, 0);
  end;
end;

// -----------------------
// ----------------------- DX3D.Wave Effect
// -----------------------

procedure TDX3D.DDVisWave;
var
  mat:D3DMATRIX;
  ys,yc:Single;     //回転用、サイン・コサインの値
  LVs:Array[0..1280] of D3DLVertex; //ポリゴンの座標
  CM1,CM2:single; // 色混合率
  cr,cg,cb:byte;
  Alpha:single;

{ ソリッドモード専用
  Vs:Array[0..1280] of D3DVertex; //ポリゴンの座標
  mtrl:D3DMATERIAL7;      //マテリアルについての情報を格納する構造体
  light0:D3DLIGHT7;
  pos1,pos2,pos3:D3DVECTOR;
}

  Cnt,HisCnt:integer;
  Vertex:array[0..WaveMax,0..WaveHisMax] of WaveVertex;
begin
  //ワールド行列の変更、y軸回りに回転
  ys:=Sin(Rot/1.4);
  yc:=Cos(Rot/1.4);
  with mat do begin
    _11:=yc; _12:=0;  _13:=ys;  _14:=0;
    _21:=0;  _22:=1;  _23:= 0;   _24:=0;
    _31:=-ys; _32:=0;  _33:=yc;  _34:=0;
    _41:=0;  _42:=0;  _43:= 0;   _44:=1;
  end;
  asm finit; end;
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);

  for cnt:=0 to WaveMax do begin
    for HisCnt:=0 to WaveHisMax-8-1 do begin
      Wave[cnt][HisCnt]:=Wave[cnt][HisCnt+1];
      WaveColor[cnt][HisCnt]:=WaveColor[cnt][HisCnt+1];
    end;
  end;

  for cnt:=0 to WaveMax do begin
    for HisCnt:=WaveHisMax downto WaveHisMax-8+1 do begin
      Wave[cnt][HisCnt]:=Wave[cnt][HisCnt-1];
      WaveColor[cnt][HisCnt]:=WaveColor[cnt][HisCnt-1];
    end;
  end;

  for cnt:=0 to WaveMax do begin
    Wave[cnt][WaveHisMax-8]:=(Vis.PSetVisual.SpeAna[Cnt].Delay/$ff-0.5)*4;
    CM1:=Cnt/WaveMax;
    CM2:=1.0-CM1;
    cr:=trunc(c1r*CM1+c2r*CM2);
    cg:=trunc(c1g*CM1+c2g*CM2);
    cb:=trunc(c1b*CM1+c2b*CM2);
    WaveColor[cnt][WaveHisMax-8]:=cr*$10000+cg*$100+cb;
  end;

  for cnt:=0 to WaveMax do begin
    for HisCnt:=0 to WaveHisMax do begin
      with Vertex[cnt][HisCnt] do begin
        if Cnt<8 then begin
          Alpha:=Cnt/8;
          end else begin
          if Cnt>(WaveMax-8) then begin
            Alpha:=(WaveMax-Cnt)/8;
            end else begin
            Alpha:=1.0;
          end;
        end;
        if HisCnt<8 then begin
          Alpha:=Alpha*(HisCnt/8);
          end else begin
          if HisCnt>(WaveHisMax-8) then begin
            Alpha:=Alpha*(WaveHisMax-HisCnt)/8;
          end;
        end;
        Alpha:=Alpha*(Wave[cnt][HisCnt]/$ff/4+(3/4));
        col:=WaveColor[cnt][HisCnt]+(trunc(Alpha*$ff) shl 24);
        pos.x:=(cnt-(WaveMax/2))/4;
        pos.y:=Wave[cnt][HisCnt];
        pos.z:=(HisCnt-(WaveHisMax/2))/4;
      end;
    end;
  end;

  if 0<>0 then begin // solid mode
{
    for cnt:=0 to WaveMax-1 do begin
      for HisCnt:=0 to WaveHisMax-1 do begin
        pos1:=Vertex[cnt+0][HisCnt+0].pos;
        pos2:=Vertex[cnt+1][HisCnt+0].pos;
        pos3:=Vertex[cnt+0][HisCnt+1].pos;
        Vertex[cnt+0][HisCnt+1].n:=MakeNormalizeVector(pos1,pos2,pos3);
      end;
    end;

    //マテリアル
    ZeroMemory(@mtrl, sizeof(mtrl));
    with mtrl do begin
      dcvAmbient:=MakeColorValue(1.0, 0.6, 0.6, 0.6);
      dcvDiffuse:=MakeColorValue(1.0, 0.6, 0.6, 0.6);
      dcvSpecular:=MakeColorValue(1.0, 0.4, 0.4, 0.4);
      dcvEmissive:=MakeColorValue(1.0, 0.0, 0.0, 0.0);
      dvPower:=5.0;
    end;
    DDraw.D3DDevice.SetMaterial(@mtrl);

    //光源…それぞれのパラメータと、マテリアルに指定された値の積が画面に出ます
    ZeroMemory(@light0, Sizeof(light0));
    with light0 do begin
      dcvAmbient:=MakeColorValue(1.0, 0.7, 0.7, 0.7);
      dcvDiffuse:=MakeColorValue(1.0, 0.3, 0.3, 0.3);
      dcvSpecular:=MakeColorValue(1.0, 1.0, 1.0, 1.0);
      dltType:=D3DLIGHT_DIRECTIONAL;
      dvDirection:=NowNormalizeVector(MakeVector(0.0, 1, 0));
      dvRange:=10000; //適当に、遠くへ
    end;
    //Direct3Dに渡す
    DDraw.D3DDevice.SetLight(0, @light0);  //0番の光源としてセット
    DDraw.D3DDevice.LightEnable(0,True);  //0番の光源をEnableにする。

    DDraw.D3DDevice.SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
    DDraw.D3DDevice.SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
    DDraw.D3DDevice.SetRenderState(D3DRENDERSTATE_CULLMODE, Integer(D3DCULL_NONE));

    for cnt:=0 to WaveMax-2 do begin
      if Main.PCMRenderFlag=False then Main.RenderWave(Main.PCMBufSize);
      for HisCnt:=0 to WaveHisMax-2 do begin
        with Vertex[cnt+0][HisCnt+0] do
          Vs[0]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        with Vertex[cnt+1][HisCnt+0] do
          Vs[1]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        with Vertex[cnt+0][HisCnt+1] do
          Vs[2]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        asm finit; end;
        DDraw.D3DDevice.DrawPrimitive(D3DPT_TRIANGLELIST,D3DFVF_VERTEX,@Vs,3, 0);
        with Vertex[cnt+1][HisCnt+1] do
          Vs[0]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        with Vertex[cnt+0][HisCnt+1] do
          Vs[1]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        with Vertex[cnt+1][HisCnt+0] do
          Vs[2]:=MakeVertex(pos.x,pos.y,pos.z,n.x,n.y,n.z,0,0);
        asm finit; end;
        DDraw.D3DDevice.DrawPrimitive(D3DPT_TRIANGLELIST,D3DFVF_VERTEX,@Vs,3, 0);
      end;
    end;
}

    end else begin // line mode
    for cnt:=0 to WaveMax do begin
      for HisCnt:=0 to WaveHisMax do begin
        with Vertex[cnt][HisCnt] do begin
          LVs[HisCnt]:=MakeLVertex(pos.x,pos.y,pos.z, col,0, 0,0);
        end;
      end;
      asm finit; end;
      DDraw.D3DDevice.DrawPrimitive(D3DPT_LINESTRIP,D3DFVF_LVERTEX,@LVs,WaveHisMax+1, 0);
    end;
    for HisCnt:=0 to WaveHisMax do begin
      for cnt:=0 to WaveMax do begin
        with Vertex[cnt][HisCnt] do begin
          LVs[Cnt]:=MakeLVertex(pos.x,pos.y,pos.z, col,0, 0,0);
        end;
      end;
      asm finit; end;
      DDraw.D3DDevice.DrawPrimitive(D3DPT_LINESTRIP,D3DFVF_LVERTEX,@LVs,WaveMax+1, 0);
    end;
  end;
end;

// -----------------------
// ----------------------- DX3D.Fly Effect
// -----------------------

procedure TDX3D.DDVisFly;
var
  mat:D3DMATRIX;
  rx,ry,xs,xc,ys,yc:Single;     //回転用、サイン・コサインの値
  Vs:Array[0..128] of D3DLVertex; //ポリゴンの座標
  CM1,CM2:single; // 色混合率
  cr,cg,cb:byte;
  LineColor:dword;
  Alpha:byte;
  vid:single;

  Cnt,HisCnt:integer;
  pos,Look:D3DVECTOR;
begin
  FlyCamera.LocateIndex:=0;
  FlyCamera.TargetIndex:=1;

  if RotAuto=False then begin
    pos:=Fly[FlyCamera.LocateIndex].Loc;
    Look:=NowLookAt(pos,Fly[FlyCamera.TargetIndex].Loc,1);
    with Look do begin
      ry:=ArcCos(z/sqrt(x*x+z*z));
      if x<0 then ry:=PI*2-ry;
      z:=sin(ry)*x+cos(ry)*z; // x軸は使わないから省略
      rx:=ArcCos(z/sqrt(z*z+y*y));
      if y<0 then rx:=PI*2-rx;
      rx:=-rx;
    end;

    //ビュー行列 … x軸周りを回転
    xs:=Sin(rx);
    xc:=Cos(rx);
    with mat do begin
      _11:=1; _12:=0;  _13:= 0;  _14:=0;
      _21:=0; _22:=xc; _23:=-xs; _24:=0;
      _31:=0; _32:=xs; _33:=xc;  _34:=0;
      _41:=0; _42:=0;  _43:=0;   _44:=1;
    end;
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

    //ワールド行列の変更、y軸回りに回転
    ys:=Sin(ry);
    yc:=Cos(ry);
    with mat do begin
      _11:=yc;  _12:=0; _13:=ys; _14:=0;
      _21:=0;   _22:=1; _23:= 0; _24:=0;
      _31:=-ys; _32:=0; _33:=yc; _34:=0;
      _41:=0;   _42:=0; _43:= 0; _44:=1;
    end;
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);

    end else begin // UserRotation

    pos.x:=0;
    pos.y:=0;
    pos.z:=0;

    //ビュー行列 … x軸周りを回転
    xs:=Sin(0);
    xc:=Cos(0);
    with mat do begin
      _11:=1; _12:=0;  _13:= 0;  _14:=0;
      _21:=0; _22:=xc; _23:=-xs; _24:=0;
      _31:=0; _32:=xs; _33:=xc;  _34:=0;
      _41:=0; _42:=0;  _43:=20;   _44:=1;
    end;
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

    //ワールド行列の変更、y軸回りに回転
    ys:=Sin(Rot/1.4);
    yc:=Cos(Rot/1.4);
    with mat do begin
      _11:=yc; _12:=0;  _13:=ys;  _14:=0;
      _21:=0;  _22:=1;  _23:= 0;   _24:=0;
      _31:=-ys; _32:=0;  _33:=yc;  _34:=0;
      _41:=0;  _42:=8;  _43:= 0;   _44:=1;
    end;
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);
  end;

  for cnt:=0 to FlyMax do begin
    for HisCnt:=FlyHisMax downto 1 do begin
      FlyHisLoc[cnt,HisCnt]:=FlyHisLoc[cnt,HisCnt-1];
    end;
    FlyHisLoc[cnt,0]:=Fly[cnt].Loc;
  end;

  for cnt:=0 to FlyMax do begin
    with Fly[cnt] do begin
      vid:=(256-Vis.PSetVisual.SpeAna[Cnt].NowY)/4+150;
      Speed.x:=(Speed.x+(Grav.x-Loc.x)/vid)*0.98;
      Speed.y:=(Speed.y+(Grav.y-Loc.y)/vid)*0.98;
      Speed.z:=(Speed.z+(Grav.z-Loc.z)/vid)*0.98;
      Loc.x:=Loc.x+Speed.x;
      Loc.y:=Loc.y+Speed.y;
      Loc.z:=Loc.z+Speed.z;
      if (abs(Loc.x-Grav.x)+abs(Loc.y-Grav.y)+abs(Loc.z-Grav.z))<3 then
        Grav:=MakeVectorPos((random(2000)-1000)/100,(random(2000)-1000)/100,(random(2000)-1000)/100);
    end;
  end;

  for cnt:=0 to FlyMax do begin
    CM1:=Cnt/FlyMax;
    CM2:=1.0-CM1;
    cr:=trunc(c1r*CM1+c2r*CM2);
    cg:=trunc(c1g*CM1+c2g*CM2);
    cb:=trunc(c1b*CM1+c2b*CM2);
    LineColor:=cr*$10000+cg*$100+cb;

    with Fly[cnt].Loc do
      Vs[0]:=MakeLVertex(x-pos.x,y-pos.y,z-pos.z,  LineColor+(dword($00) shl 24),0, 0,0);

    for HisCnt:=0 to FlyHisMax do begin
      Alpha:=$ff-(HisCnt*$ff div FlyHisMax);
      with FlyHisLoc[cnt,HisCnt] do
        Vs[HisCnt+1]:=MakeLVertex(x-pos.x,y-pos.y,z-pos.z,  LineColor+(Alpha shl 24),0, 0,0);
    end;
    asm finit; end;
    DDraw.D3DDevice.DrawPrimitive(D3DPT_LINESTRIP,D3DFVF_LVERTEX,@Vs,FlyHisMax+2, 0);
  end;
end;

// -----------------------
// ----------------------- DX3D.Pool Effect
// -----------------------

procedure TDX3D.DDVisPoolInit;
var
  x,z:integer;
begin
  for x:=0 to PoolPlateMax-1 do begin
    for z:=0 to PoolPlateMax-1 do begin
      with PoolPlate[x,z] do begin
        _x:=x-(PoolPlateMax/2);
        _z:=z-(PoolPlateMax/2);
        _tu:=x/PoolPlateMax*1;
        _tv:=z/PoolPlateMax*1;
      end;
      Poolwave1.y[x,z]:=0;
      Poolwave2.y[x,z]:=0;
      Poolwave3.y[x,z]:=0;
    end;
  end;

  PoolArgCnt:=0;
  for x:=0 to PoolPlateMax-2 do begin
    for z:=0 to PoolPlateMax-1 do begin
      PoolVsIdx[PoolArgCnt+0]:=((x+1)*PoolPlateMax)+z;
      PoolVsIdx[PoolArgCnt+1]:=((x+0)*PoolPlateMax)+z;
      inc(PoolArgCnt,2);
    end;
  end;
end;

procedure TDX3D.DDVisPoolFree;
begin
end;

procedure TDX3D.DDVisPool;
var
  mat,matpos:D3DMATRIX;
  Vs:Array[0..PoolPlateMax*PoolPlateMax] of D3DVertex; //ポリゴンの座標
  v0,v1,v2:D3DVECTOR;
  vr:D3DVECTOR;
  ch:integer;

  ys,yc:single;

  cx,cz:integer;
begin
  DDVisPoolRaiseWave(random(PoolPlateMax),random(PoolPlateMax),0.1);

  for ch:=0 to 7 do begin
    if (Vis.PSetVisual.NoteKeyno[ch])<>0 then
      DDVisPoolRaiseWave((Vis.PSetVisual.NoteKeyno[ch]*PoolPlateMax) div 6144,((ch+1)*PoolPlateMax div 9),1.5);
  end;

  DDVisPoolCalculateWave;

  if RotAuto=True then begin
    //ビュー行列
    with mat do begin
      _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:=8; _43:=30; _44:=1;
    end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

    end else begin // UserRotation

    //ワールド行列の変更、y軸回りに回転
    ys:=Sin(Rot/1.4);
    yc:=Cos(Rot/1.4);
    with mat do begin
      _11:=yc; _12:=0;  _13:=ys;  _14:=0;
      _21:=0;  _22:=1;  _23:= 0;   _24:=0;
      _31:=-ys; _32:=0;  _33:=yc;  _34:=0;
      _41:=0;  _42:=0;  _43:=0;   _44:=1;
    end;
    with matpos do begin
      _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:=8; _43:=30; _44:=1;
    end;
    mat:=ModulateMatrix(mat,matpos);
    asm finit; end;
    DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);
  end;

  //ワールド行列の変更、y*x回転
  mat:=MakeRotxMatrix(-120/640*PI*2);
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);

  DDraw.D3DDevice.SetTexture(0, SeaWaveTex[SeaWaveCnt].Surface);

  for cx:=0 to PoolPlateMax-1 do begin
    for cz:=0 to PoolPlateMax-1 do begin
      with PoolPlate[cx,cz] do begin
        v0:=MakeVector(_x-0.5, Poolwave1.y[cx+0,cz+0], _z-0.5);
        v1:=MakeVector(_x-0.5, Poolwave1.y[cx+0,cz+1], _z+0.5);
        v2:=MakeVector(_x+0.5, Poolwave1.y[cx+1,cz+1], _z+0.5);
        vr:=MakeNormalizeVector(v0,v1,v2);
        with Vs[(cx*PoolPlateMax)+cz] do begin
          x:=v0.x;
          y:=v0.y;
          z:=v0.z;
          nx:=vr.x;
          ny:=vr.y;
          nz:=vr.z;
          vr:=ModulateVectorMatrix(vr,mat);
          tu:=_tu+(cos(vr.x*PI/2)*v0.y/10);
          tv:=_tv+(cos(vr.z*PI/2)*v0.y/10);
        end;
      end;
    end;
  end;

  asm finit; end;
  DDraw.D3DDevice.DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,D3DFVF_VERTEX,@Vs,PoolPlateMax*PoolPlateMax-1,@PoolVsIdx,PoolArgCnt, 0);
end;

procedure TDX3D.DDVisPoolCalculateWave;
var
  cx,cz:integer;
  Poolwavet:TPoolwave;
begin
  for cz:=1 to PoolPlateMax-2 do begin
    for cx:=1 to PoolPlateMax-2 do begin
      with Poolwave2 do
        Poolwave3.y[cx,cz]:=(((y[cx,cz-1]+y[cx,cz+1]+y[cx-1,cz]+y[cx+1,cz])/4*2)-Poolwave1.y[cx,cz])*0.9;
    end;
  end;

  Poolwavet:=Poolwave1;
  Poolwave1:=Poolwave2;
  Poolwave2:=Poolwave3;
  Poolwave3:=Poolwavet;
end;

procedure TDX3D.DDVisPoolRaisewave(cx,cz:integer;Height:single);
var
  StartSize:integer;
  x,z,px,pz:integer;
  r:single;
begin
  StartSize:=6;
  for z:=-StartSize to StartSize do begin
    for x:=-StartSize to StartSize do begin
      r:=(x*x)+(z*z);
      if (r<=(StartSize*StartSize)) then begin
        px:=cx+x;
        pz:=cz+z;
        if (1<=px) and (px<=(PoolPlateMax-2)) and (1<=pz) and (pz<=(PoolPlateMax-2)) then begin
          Poolwave2.y[px,pz]:=Poolwave2.y[px,pz]+((cos(sqrt(r)/StartSize*PI/2))*Height);
        end;
      end;
    end;
  end;
end;

// -----------------------
// ----------------------- DX3D.Box Effect
// -----------------------

procedure TDX3D.DDVisBoxInit;
var
  x,z:integer;
  function AddV(_x,_y,_z,_nx,_ny,_nz,_tu,_tv:single):D3DVertex;
  begin
    BoxOneVs[BoxOneVsCnt]:=MakeVertex(_x*Boxpx,_y*Boxpy,_z*Boxpz,_nx,_ny,_nz,_tu,_tv);
    inc(BoxOneVsCnt);
  end;
begin
  for x:=0 to BoxChMax-1 do begin
    for z:=0 to BoxNoteMax-1 do begin
      BoxHeight[x,z]:=0;
    end;
  end;

  // 初期ボックス作成
  BoxOneVsCnt:=0;
  // +y面
  AddV(-1,+1,+1,  0, 1, 0, 0,1);
  AddV(+1,+1,+1,  0, 1, 0, 1,1);
  AddV(-1,+1,-1,  0, 1, 0, 0,0);
  AddV(+1,+1,-1,  0, 1, 0, 1,0);
  AddV(-1,+1,-1,  0, 1, 0, 0,0);
  AddV(+1,+1,+1,  0, 1, 0, 1,1);
  // -y面
  AddV(+1,-1,+1,  0,-1, 0, 1,1);
  AddV(-1,-1,+1,  0,-1, 0, 0,1);
  AddV(-1,-1,-1,  0,-1, 0, 0,0);
  AddV(-1,-1,-1,  0,-1, 0, 0,0);
  AddV(+1,-1,-1,  0,-1, 0, 1,0);
  AddV(+1,-1,+1,  0,-1, 0, 1,1);
  // -x面
  AddV(-1,-1,+1, -1, 0, 0, 0,1);
  AddV(-1,+1,+1, -1, 0, 0, 1,1);
  AddV(-1,-1,-1, -1, 0, 0, 0,0);
  AddV(-1,+1,-1, -1, 0, 0, 1,0);
  AddV(-1,-1,-1, -1, 0, 0, 0,0);
  AddV(-1,+1,+1, -1, 0, 0, 1,1);
  // +x面
  AddV(+1,+1,+1,  1, 0, 0, 1,1);
  AddV(+1,-1,+1,  1, 0, 0, 0,1);
  AddV(+1,-1,-1,  1, 0, 0, 0,0);
  AddV(+1,-1,-1,  1, 0, 0, 0,0);
  AddV(+1,+1,-1,  1, 0, 0, 1,0);
  AddV(+1,+1,+1,  1, 0, 0, 1,1);
  // -z面
  AddV(+1,+1,-1,  0, 0,-1, 1,1);
  AddV(+1,-1,-1,  0, 0,-1, 1,0);
  AddV(-1,-1,-1,  0, 0,-1, 0,0);
  AddV(-1,-1,-1,  0, 0,-1, 0,0);
  AddV(-1,+1,-1,  0, 0,-1, 0,1);
  AddV(+1,+1,-1,  0, 0,-1, 1,1);
  // +z面
  AddV(+1,-1,+1,  0, 0, 1, 1,0);
  AddV(+1,+1,+1,  0, 0, 1, 1,1);
  AddV(-1,-1,+1,  0, 0, 1, 0,0);
  AddV(-1,+1,+1,  0, 0, 1, 0,1);
  AddV(-1,-1,+1,  0, 0, 1, 0,0);
  AddV(+1,+1,+1,  0, 0, 1, 1,1);
end;

procedure TDX3D.DDVisBoxFree;
begin
end;

procedure TDX3D.DDVisBox;
var
  Ch,Note,i:integer;
  mat,worldmat,maty:D3DMATRIX;
  BoxTemp:array[0..BoxChMax,0..BoxNoteMax*BoxNoteMul] of single;
  Height:single;
begin
  //ビュー行列
  with mat do begin
    _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:=5; _43:=20; _44:=1;
  end;
  mat:=ModulateMatrix(MakeRotxMatrix(-1.0),mat);
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

  maty:=MakeRotyMatrix(rot);

  for Ch:=0 to 7 do begin
    if (Vis.PSetVisual.NoteKeyno[ch])<>0 then begin
      Note:=(Vis.PSetVisual.NoteKeyno[ch]*BoxNoteMax*BoxNoteMul) div 6144;
      if ((0<=Note) and (Note<(BoxNoteMax*BoxNoteMul))) then BoxHeight[Ch,Note]:=(BoxHeight[Ch,Note]/2+10)/1;
    end;
  end;

  for Ch:=0 to BoxChMax-1 do begin
    for Note:=0 to BoxNoteMax*BoxNoteMul-1 do begin
      BoxTemp[Ch,Note]:=BoxHeight[Ch,Note]*0.9;
    end;
    for Note:=1 to BoxNoteMax*BoxNoteMul-2 do begin
      BoxHeight[Ch,Note]:=(BoxTemp[Ch,Note-1]*2+BoxTemp[Ch,Note]*1+BoxTemp[Ch,Note+1]*2)/5;
    end;
  end;

  for Ch:=0 to BoxChMax-1 do begin
    for Note:=0 to BoxNoteMax-1 do begin
      Height:=0;
      for i:=0 to BoxNoteMul-1 do begin
        Height:=Height+BoxHeight[Ch,Note*BoxNoteMul+i];
      end;
      Height:=Height/BoxNoteMul;
      worldmat:=NowIdentityMatrix;
      with worldmat do begin
        _41:=Note*2-BoxNoteMax; _42:=Height;   _43:=(Ch*2-BoxChMax)*2;
      end;
      worldmat:=ModulateMatrix(MakeRotxMatrix(Height/8),worldmat);
      worldmat:=ModulateMatrix(MakeRotyMatrix(Height/8),worldmat);
      worldmat:=ModulateMatrix(worldmat,maty);
      DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @worldmat);
      DDraw.D3DDevice.DrawPrimitive(D3DPT_TRIANGLELIST,D3DFVF_VERTEX,@BoxOneVs,BoxOneVsCnt, 0);
    end;
  end;
end;

// -----------------------
// ----------------------- DX3D.Rain Effect
// -----------------------

procedure TDX3D.DDVisRainInit;
var
  ch,cnt:integer;
  x,y,z:integer;
  r:single;
begin
  if Rain=nil then Rain:=TRain.Create;
  Rain.SetWaterColor($000000,Images.HSVMapBM);
  Rain.InitWater(512);

  Rain.InitPlate(8*$20);
  for ch:=0 to 8-1 do begin
    x:=$80+(((ch mod 2)*2-1)*(5-(ch div 2))*$20);
    y:=(ch div 2)*$30+$20;
    r:=-((ch mod 2)*2-1)*(PI*0.5);
    for cnt:=0 to $10-1 do begin
      z:=cnt*$10;
      Rain.SetPlate(ch*$10+cnt,x,y,z,r,$40,$0f);
    end;
  end;

  Rain.SetReflect(1);
end;

procedure TDX3D.DDVisRainFree;
begin
  Rain.Free;
  Rain:=nil;
end;

procedure TDX3D.DDVisRain;
var
  cnt:integer;
  Ch,idx,Note,i:integer;
  matpos,mat,worldmat,maty:D3DMATRIX;
  BoxTemp:array[0..BoxChMax,0..BoxNoteMax*BoxNoteMul] of single;
  Height:single;
  Vs:Array[0..20480] of D3DLVertex; //ポリゴンの座標
  PlateVs:array[0..6] of D3DVertex;
  Alpha:dword;
  ys,yc:single;
  col:dword;
  r:single;
  plx,ply,plz,plx1,ply1,plz1,plx2,ply2,plz2:single;
  plnx,plny:single;
begin
//  Rot:=0;
  //ワールド行列の変更、y軸回りに回転
  ys:=Sin(Rot/3);
  yc:=Cos(Rot/3);
  with mat do begin
    _11:=yc; _12:=0;  _13:=ys;  _14:=0;
    _21:=0;  _22:=1;  _23:= 0;   _24:=0;
    _31:=-ys; _32:=0;  _33:=yc;  _34:=0;
    _41:=0;  _42:=0;  _43:=0;   _44:=1;
  end;
  with matpos do begin
    _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:=-10; _43:=$ff; _44:=1;
  end;
  mat:=ModulateMatrix(mat,matpos);
  asm finit; end;
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, @mat);

  //ワールド行列の変更、y*x回転
  mat:=MakeRotxMatrix(-0.03*PI*2);
  DDraw.D3DDevice.SetTransform(D3DTRANSFORMSTATE_WORLD, @mat);

  maty:=MakeRotyMatrix(rot);

  Rain.CalcWater;
  Rain.BlockWater;
//  Rain.DrawWater(PrvImg.Picture.Bitmap);
//  Rain.DrawPlate(PrvImg.Picture.Bitmap);

  Alpha:=$ff;
  Alpha:=Alpha shl 24;
  col:=$8080a0+Alpha;
  for cnt:=-4 to 4 do begin
    Vs[(cnt+4)*2+0]:=MakeLVertex(-$80,-$80,(cnt*$80 div 4),  col,0, 0,0);
    Vs[(cnt+4)*2+1]:=MakeLVertex( $80,-$80,(cnt*$80 div 4),  col,0, 0,0);
  end;
  DDraw.D3DDevice.DrawPrimitive(D3DPT_LINELIST,D3DFVF_LVERTEX,@Vs,(8+1)*2, 0);
  for cnt:=-4 to 4 do begin
    Vs[(cnt+4)*2+0]:=MakeLVertex((cnt*$80 div 4),-$80,-$80,  col,0, 0,0);
    Vs[(cnt+4)*2+1]:=MakeLVertex((cnt*$80 div 4),-$80, $80,  col,0, 0,0);
  end;
  DDraw.D3DDevice.DrawPrimitive(D3DPT_LINELIST,D3DFVF_LVERTEX,@Vs,(8+1)*2, 0);

  for ch:=0 to 7 do begin
    for cnt:=0 to $10-1 do begin
      idx:=ch*$10+cnt;
      r:=abs(Rain.Plate[idx].r)-(PI*0.1);
      r:=r*0.95+(PI*0.1);
      Rain.SetRotPlate(idx,-((ch mod 2)*2-1)*r);
    end;
    if (Vis.PSetVisual.NoteKeyno[ch])<>0 then begin
      cnt:=(Vis.PSetVisual.NoteKeyno[ch]*$18) div 6144;
      cnt:=cnt-$04;
      if ($01<=cnt) and (cnt<$0f) then begin
        idx:=ch*$10+cnt;
        r:=abs(Rain.Plate[idx].r)-(PI*0.45);
        r:=r*0.8+(PI*0.45);
        Rain.SetRotPlate(idx,-((ch mod 2)*2-1)*r);
        idx:=ch*$10+cnt-1;
        r:=abs(Rain.Plate[idx].r)-(PI*0.3);
        r:=r*0.8+(PI*0.3);
        Rain.SetRotPlate(idx,-((ch mod 2)*2-1)*r);
        idx:=ch*$10+cnt+1;
        r:=abs(Rain.Plate[idx].r)-(PI*0.3);
        r:=r*0.8+(PI*0.3);
        Rain.SetRotPlate(idx,-((ch mod 2)*2-1)*r);
      end;
    end;
  end;

  Alpha:=$ff;
  Alpha:=Alpha shl 24;
  for cnt:=0 to Rain.WaterCount-1 do begin
    with Rain.Water[cnt] do begin
      col:=Rain.WaterColor[leave]+Alpha;
//      col:=$ffffff+Alpha;
      Vs[cnt*2+0]:=MakeLVertex(lx-$80,-(ly-$80),lz-$80,  col,0, 0,0);
      Vs[cnt*2+1]:=MakeLVertex(nx-$80,-(ny-$80),nz-$80,  col,0, 0,0);
    end;
  end;
  DDraw.D3DDevice.DrawPrimitive(D3DPT_LINELIST,D3DFVF_LVERTEX,@Vs,Rain.WaterCount*2, 0);

  with DDraw.D3DDevice do begin
    //レンダリングステートの設定
    SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
    SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
    SetRenderState( D3DRENDERSTATE_NORMALIZENORMALS, Integer(False) );
    SetRenderState(D3DRENDERSTATE_CULLMODE, Integer(D3DCULL_CCW));

    SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, Integer(True) );
  end;

  for cnt:=0 to Rain.PlateCount-1 do begin
    with Rain.Plate[cnt] do begin
      if r<0 then begin
        plnx:=sin(r+(PI/2));
        plny:=cos(r+(PI/2));
        plx1:=x1-$80;
        ply1:=-(y1-$80);
        plz1:=z1-$80;
        plx2:=x2-$80;
        ply2:=-(y2-$80);
        plz2:=z2-$80;
        end else begin
        plnx:=-sin(r+(PI/2));
        plny:=-cos(r+(PI/2));
        plx2:=x1-$80;
        ply2:=-(y1-$80);
        plz1:=z1-$80;
        plx1:=x2-$80;
        ply1:=-(y2-$80);
        plz2:=z2-$80;
      end;

      PlateVs[0]:=MakeVertex(plx1,ply1,plz1,plnx,plny,0,0,0);
      PlateVs[1]:=MakeVertex(plx2,ply2,plz1,plnx,plny,0,0,0);
      PlateVs[2]:=MakeVertex(plx2,ply2,plz2,plnx,plny,0,0,0);

      PlateVs[3]:=MakeVertex(plx1,ply1,plz1,plnx,plny,0,0,0);
      PlateVs[4]:=MakeVertex(plx2,ply2,plz2,plnx,plny,0,0,0);
      PlateVs[5]:=MakeVertex(plx1,ply1,plz2,plnx,plny,0,0,0);
    end;
    DDraw.D3DDevice.DrawPrimitive(D3DPT_TRIANGLELIST,D3DFVF_VERTEX,@PlateVs,6, 0);
  end;

  with DDraw.D3DDevice do begin
    //レンダリングステートの設定
    SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(False));
    SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(False) );
    SetRenderState( D3DRENDERSTATE_DITHERENABLE, Integer(True));
    SetRenderState( D3DRENDERSTATE_SHADEMODE, Integer(D3DSHADE_GOURAUD));
    SetRenderState( D3DRENDERSTATE_NORMALIZENORMALS, Integer(False) );
    SetRenderState(D3DRENDERSTATE_CULLMODE, Integer(D3DCULL_NONE));

    SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, Integer(False) );
  end;

end;

end.
