unit kyukyu1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DDraw, OLE2, d3d,d3dcaps,d3dtypes, ddsd, dddd,dsound, MMSystem,
  s_Mathpack, SXLib;

type
  TForm1 = class(TForm)
    DDDD1: TDDDD;
    DDSD1: TDDSD;
    procedure DDDD1Init(Sender: TObject; fNeedChange: Boolean);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    Scene:TSXScene;           //シーンオブジェクト
    Root,Camera,Car:TSXFrame; //ルート・カメラ・救急車のフレーム

    CarMesh:TSXMesh;

    Lights:TSXLightGroup;
    Mtrl:TSXMaterial;

    Silen:TDDSDWave3D;

    procedure AppIdle(Sender:TObject; var Done:Boolean);
  end;

var
  Form1: TForm1;

  prevT:Integer = 0; //フレームレート計算用

implementation

//メインループ
procedure TForm1.AppIdle(Sender:TObject; var Done:Boolean);
var
  pos:D3DVector;
  cur,e:Integer;  //現在時刻,前の描画からの相対時刻
begin

  //前にこのループを通ってから、どれだけ経過したかを計算
  cur:=TimeGetTime(); //MMSystemの関数を使って、現在時刻をms単位で知る
  if prevT = 0 then
    e:=30             //初回はとりあえず30msとしておく
  else
    e:=cur - prevT;
  prevT:=cur;

  //サイレンを鳴らす
  if DDSD1[0].Status And DSBSTATUS_PLAYING = 0 then
    DDSD1[0].LoopPlay;


  //秒速20メートルで移動
  pos:=Car.GetTranslation(Root);
  pos:=NowAdd(pos, Vector( 20.0 * e / 1000.0, 0,0) );

  //もしも、+50mまで行ったら、-50mまで引き返す
  if pos.x > 50.0 then
    pos.x:=-50;
  Car.SetTranslation(Root,pos);

  //救急車の位置・速度に、サイレンの位置・速度をあわせる
  DDSD1[0].Params3D.Position:=pos;
  DDSD1[0].Params3D.Velocity:=Vector(20,0,0);



  (* クリア *)
  Scene.Clear(D3DCLEAR_TARGET + D3DCLEAR_ZBUFFER, $FF000000, 1.0, 0);

  (* レンダリング *)
  asm finit; end;
  DDDD1.D3DDevice.BeginScene;
  asm finit; end;

  Scene.Render(Root);

  asm finit; end;
  DDDD1.D3DDevice.EndScene;
  asm finit; end;


  (* フリップして終わり〜 *)
  DDDD1.Flip;

  Done:=False;
end;

{$R *.DFM}

procedure TForm1.DDDD1Init(Sender: TObject; fNeedChange: Boolean);
begin

  //シーンオブジェクトの生成
  Scene:=TSXScene.Create(DDDD1);

  Scene.SetViewPort(0,0,ClientWidth,ClientHeight);
  Scene.SetProjection(Pi/4, ClientHeight/ClientWidth, 1.0,5000.0);  //画角は90度


  //ルートフレームの作成
  Root:=TSXFrame.Create(Nil);


  //カメラの作成
  Camera:=TSXFrame.Create(Root);
  Camera.SetTranslation(Root, Vector(0,0,0)); //原点にセット
  Camera.SetOrientation(Root, Vector(0,0,1), Vector(0,1,0));
  Scene.CameraFrame:=Camera;


  //ライトの作成
  Lights:=TSXLightGroup.Create(DDDD1, 1);
  Lights[0].SetupAmbient(1.0,1.0,1.0);
  Lights[0].SetupDiffuse(1.0,1.0,1.0);
  Lights[0].SetupSpecular(1.0,1.0,1.0);
  Lights[0].SetupDirectional(Vector(0.0,0.0,1.0));
  Lights[0].Enabled:=True;


  //マテリアルの作成
  Mtrl:=TSXMaterial.Create(DDDD1);
  Mtrl.SetupAmbient(0.2,0.2,0.2);
  Mtrl.SetupDiffuse(1.0,1.0,1.0);
  Mtrl.SetupSpecular(1.0,1.0,1.0);
  Mtrl.SetupSpecularPower(10.0);


  //救急車の作成
  Car:=TSXFrame.Create(Root);
  CarMesh:=TSXMesh.Create(DDDD1);
  CarMesh.LoadFromFile('kyukyu.sx');
  Car.Mesh:=CarMesh;

  Car.SetTranslation(Root, Vector(-20.0,0.0,10.0));       //奥に10メートル、左20メートリにセット
  Car.SetOrientation(Root, Vector(1,0,0), Vector(0,1,0));



  //レンダリングステートの設定
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_LIGHTING, Integer(True));
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_ZENABLE, Integer(True) );
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_COLORVERTEX, Integer(True) );
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_SPECULARENABLE, Integer(True) );
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_SPECULARMATERIALSOURCE, Integer(D3DMCS_COLOR2));
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_DITHERENABLE, Integer(True));
  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_SHADEMODE, Integer(D3DSHADE_GOURAUD));

  DDDD1.D3DDevice.SetRenderState( D3DRENDERSTATE_NORMALIZENORMALS, Integer(True) );



  //サイレンの読み込み
  Silen:=TDDSDWave3D.Create(DDSD1,'silen.wav');
  DDSD1[0].WaveData:=Silen;

  //音の減衰具合を、ちょっと抑える
  DDSD1.Listener.RolloffFactor:=0.3;

  //メインループの取り付け
  Application.OnIdle:=AppIdle;

end;

end.
