unit Xsimplify1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  dddd, Menus, StdCtrls, ComCtrls,
  DDraw, OLE2, d3d,d3dcaps,d3dtypes,d3drm,d3drmobj,d3drmwin,d3drmdef,
  dddd3dut, ExtCtrls, SXLib;

type
  TForm1 = class(TForm)
    QD: TDDDD;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    Edit1: TEdit;
    Label1: TLabel;
    Button1: TButton;
    Edit2: TEdit;
    Label2: TLabel;
    Button2: TButton;
    Label3: TLabel;
    Button3: TButton;
    Label4: TLabel;
    Edit3: TEdit;
    CheckBox1: TCheckBox;
    RadioGroup1: TRadioGroup;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Edit3Exit(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;




var
  Form1: TForm1;
  CreaseAngle:Single = 60.0; //法線をまとめる角度

implementation

{$R *.DFM}


//変換元ファイル名ゲット
procedure TForm1.Button1Click(Sender: TObject);
begin
  with OpenDialog1 do begin
    if Execute then begin
      Edit1.Text:=FileName;
    end;
  end;
end;

//保存先ファイル名ゲット
procedure TForm1.Button2Click(Sender: TObject);
begin
  with SaveDialog1 do begin
    if Execute then begin
      Edit2.Text:=FileName;
    end;
  end;
end;

//変換〜
procedure TForm1.Button3Click(Sender: TObject);
var
  meshB:IDirect3DRMMeshBuilder3;
  face:IDirect3DRMFace2;

  nFaces,nIndices,nVerticesOnFace:Integer;
  i,j,iVertex,count:Integer;

  dvs:Array of TSXVertex; //D3DVertexの配列
  idxs:Array of Word;     //頂点インデクスの配列

  Dcount:Integer;

  Ddvs:Array of TSXVertex;    //完成品(SX)
  DdLVs:Array of D3DLVertex;   //完成品(LVertex)
  DdMTvs:Array of TSXVertexMT;  //完成品(SXMT)

  fSameVertexExists:Boolean;
  iMatchedVertex:Integer;

  fs:TFileStream;

  FVF:DWord;  //FVFフラグ
  VertexSize:DWord; //頂点のサイズ

  //面の上にあるx番の頂点を、dvsにセット
  procedure SetD3DVertex(x,idx:Integer);
  begin
    iVertex:=face.GetVertexIndex(x);

    face.GetVertex(x, @(dvs[idx].Pos), @(dvs[idx].Normal));

    meshB.GetTextureCoordinates(iVertex, dvs[idx].tu,dvs[idx].tv);

    dvs[idx].diffuse:=face.GetColor;
    dvs[idx].specular:=$FFFFFFFF;

    //インデクスのセット
    idxs[idx]:=idx;
  end;

begin
  QD.D3DRM.CreateMeshBuilder(meshB);

  Screen.Cursor:=crHourGlass;

  if meshB.Load(PChar(Edit1.Text),Nil,D3DRMLOAD_FROMFILE,Nil,Nil) <> DD_OK then begin
    MessageDlg(Edit1.Text + 'は、変換できません', mtWarning, [mbOK], 0);
    Screen.Cursor:=crDefault;
    Exit;
  end;


  //法線の生成
  Label3.Caption:='法線の生成';
  Label3.Update;

  if CheckBox1.Checked then
    meshB.GenerateNormals(CreaseAngle / 180.0 * Pi, D3DRMGENERATENORMALS_USECREASEANGLE + D3DRMGENERATENORMALS_PRECOMPACT)
  else
    meshB.GenerateNormals(CreaseAngle / 180.0 * Pi, D3DRMGENERATENORMALS_PRECOMPACT);



  //面を全て三角形に分割した場合の頂点の個数を計算
  Label3.Caption:='頂点数の計算';
  Label3.Update;

  nIndices:=0;
  nFaces:=meshB.GetFaceCount;
  For i:=0 to nFaces-1 do begin
    meshB.GetFace(i, face);
    nVerticesOnFace:=face.GetVertexCount;

    if nVerticesOnFace >= 3 then
      Inc(nIndices, (nVerticesOnFace-2) * 3);
    face.Release;
  end;

  SetLength(idxs, nIndices);
  SetLength(dvs,  nIndices);


  //三角形に分割しつつ、D3Dvertexの羅列を作る。
  Label3.Caption:='三角形に分割';
  Label3.Update;

  count:=0;
  For i:=0 to nFaces-1 do begin
    meshB.GetFace(i, face);
    nVerticesOnFace:=face.GetVertexCount;

    For j:=0 to nVerticesOnFace-3 do begin
      SetD3DVertex(0, count);   Inc(count);
      SetD3DVertex(j+1, count); Inc(count);
      SetD3DVertex(j+2, count); Inc(count);
    end;
  end;


  SetLength(Ddvs,  nIndices);

  //同じ頂点を纏める
  Label3.Caption:='頂点のコンパクション';
  Label3.Update;

  Dcount:=0;
  For i:=0 to nIndices-1 do begin

    //同じ頂点が今までに格納されてないか調べる
    fSameVertexExists:=False;
    For j:=0 to Dcount-1 do begin
      if CompareMem(@dvs[i],@Ddvs[j],Sizeof(TSXvertex)) then begin
        fSameVertexExists:=True;
        iMatchedVertex:=j;

        idxs[i]:=iMatchedVertex;
        break;
      end;
    end;

    if not fSameVertexExists then begin
      //同じ頂点が無いなら、頂点リストに追加
      Ddvs[Dcount]:=dvs[i];

      //インデクスリストの修正
      idxs[i]:=DCount;

      Inc(DCount);
    end;


    if i Mod 256 = 0 then begin
      Label3.Caption:='頂点のコンパクション' + Format('%6d / %6d',[i,nIndices]);
      Label3.Update;
    end;
  end;


  //ファイルへのカキコ
  Label3.Caption:='ファイルへ書き込み中';
  Label3.Update;

  try
    fs:=TFileStream.Create(Edit2.Text, fmCreate);

    //ヘッダのカキコ
    fs.WriteBuffer('Simplified_X01  ',16);
    fs.WriteBuffer(Word(DCount),Sizeof(Word));
    fs.WriteBuffer(Word(nIndices),Sizeof(Word));

    Case RadioGroup1.ItemIndex of
      0: begin //SXVertex
        FVF:=FVF_SXVERTEX;
        fs.WriteBuffer(FVF, Sizeof(DWord));
        VertexSize:=Sizeof(TSXVertex);
        fs.WriteBuffer(VertexSize, Sizeof(DWord));

        //頂点情報のカキコ
        fs.Seek(256,soFromBeginning);
        fs.WriteBuffer(Ddvs[0], Sizeof(TSXVertex) * DCount);
        fs.WriteBuffer(idxs[0], Sizeof(Word) * nIndices);
      end;

      1: begin //SXVertexMT
        FVF:=FVF_SXVERTEXMT;
        fs.WriteBuffer(FVF, Sizeof(DWord));
        VertexSize:=Sizeof(TSXVertexMT);
        fs.WriteBuffer(VertexSize, Sizeof(DWord));

        SetLength(DdMTvs,DCount);

        For i:=0 to DCount-1 do begin
          DdMTvs[i].pos:=Ddvs[i].pos;
          DdMTvs[i].normal:=Ddvs[i].normal;
          DdMTvs[i].diffuse:=Ddvs[i].diffuse;
          DdMTvs[i].specular:=Ddvs[i].specular;
          DdMTvs[i].tu0:=Ddvs[i].tu;
          DdMTvs[i].tv0:=Ddvs[i].tv;
          DdMTvs[i].tu1:=Ddvs[i].tu;
          DdMTvs[i].tv1:=Ddvs[i].tv;
        end;

        //頂点情報のカキコ
        fs.Seek(256,soFromBeginning);
        fs.WriteBuffer(DdMTvs[0], VertexSize * DCount);
        fs.WriteBuffer(idxs[0], Sizeof(Word) * nIndices);
      end;

      2: begin //LVertex;
        FVF:=D3DFVF_LVERTEX;
        fs.WriteBuffer(FVF, Sizeof(DWord));
        VertexSize:=Sizeof(D3DLVERTEX);
        fs.WriteBuffer(VertexSize, Sizeof(DWord));

        SetLength(DdLvs,DCount);

        For i:=0 to DCount-1 do begin
          DdLvs[i].x:=Ddvs[i].pos.x;
          DdLvs[i].y:=Ddvs[i].pos.y;
          DdLvs[i].z:=Ddvs[i].pos.z;
          DdLvs[i].dcColor:=Ddvs[i].diffuse;
          DdLvs[i].dcSpecular:=0;
          DdLvs[i].tu:=Ddvs[i].tu;
          DdLvs[i].tv:=Ddvs[i].tv;
        end;

        //頂点情報のカキコ
        fs.Seek(256,soFromBeginning);
        fs.WriteBuffer(DdLvs[0], VertexSize * DCount);
        fs.WriteBuffer(idxs[0], Sizeof(Word) * nIndices);
      end;
    end;


    fs.Free;
  except
    Label3.Caption:='ファイルに書き込めませんでした';
    Label3.Update;
    Screen.Cursor:=crDefault;
    Ddvs:=Nil;
    dvs:=Nil;
    idxs:=Nil;
    exit;
  end;




  Label3.Caption:='完了';
  Label3.Update;

  Screen.Cursor:=crDefault;



  Ddvs:=Nil;
  DdMTvs:=Nil;
  DdLvs:=Nil;

  dvs:=Nil;
  idxs:=Nil;
end;


//法線まとめダイアログ
procedure TForm1.Edit3Exit(Sender: TObject);
begin
  try
    CreaseAngle:=StrToFloat(Edit3.Text);
  except
    CreaseAngle:=0;
    Edit3.Text:='60';
  end;
end;

end.
