unit WinForm;

interface

uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data,
  Microsoft.DirectX, Microsoft.DirectX.Direct3D,Microsoft.DirectX.Direct3DX;

type
  TWinForm = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    Components: System.ComponentModel.Container;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  private
    { Private Declarations }
  public
    constructor Create;
  private
    urzadzenie : Device;
    wierzcholki: VertexBuffer;
  public
    function  InicjujGrafike: Boolean;
    procedure Rysuj;
  private
    function  UtworzBuforWierzch(var urzadzenie: Device): VertexBuffer;
    procedure WypelnijBuforWierzch(var bufor: VertexBuffer);
    procedure UstawMacierze;
    procedure UstawSwiatla;
  end;

  [assembly: RuntimeRequiredAttribute(TypeOf(TWinForm))]

implementation

{$AUTOBOX ON}

{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support -- do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TWinForm.InitializeComponent;
begin
  // 
  // TWinForm
  // 
  Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
  Self.ClientSize := System.Drawing.Size.Create(592, 566);
  Self.Name := 'TWinForm';
  Self.Text := 'DirectX.NET Przykład 8';
end;
{$ENDREGION}

procedure TWinForm.Dispose(Disposing: Boolean);
begin
  if Disposing then
  begin
    if Components <> nil then
      Components.Dispose();
  end;
  inherited Dispose(Disposing);
end;

constructor TWinForm.Create;
begin
  inherited Create;
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent;
  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

function TWinForm.InicjujGrafike: Boolean;
var
  parametry: PresentParameters;
begin
  try
    parametry:= PresentParameters.Create;
    parametry.Windowed:= True;
    parametry.SwapEffect:= Microsoft.DirectX.Direct3D.SwapEffect.Discard;
    urzadzenie:= Device.Create(0, DeviceType.Hardware, Self.Handle,
      CreateFlags.SoftwareVertexProcessing, [parametry]);
    wierzcholki:=UtworzBuforWierzch(urzadzenie);
    Result:= true;
  except
    on DirectXException do Result:=false;
  end;
end;

procedure TWinForm.Rysuj;
begin
  if (urzadzenie=nil) then Exit;

  urzadzenie.Clear(ClearFlags.Target, System.Drawing.Color.White, 1.0, 0);
  urzadzenie.BeginScene;

  UstawMacierze;
  UstawSwiatla;

  urzadzenie.SetStreamSource(0, wierzcholki, 0);
  urzadzenie.DrawPrimitives(PrimitiveType.TriangleList, 0, 16);

  urzadzenie.EndScene;
  urzadzenie.Present;
end;

function TWinForm.UtworzBuforWierzch(var urzadzenie: Device): VertexBuffer;
var bufor: VertexBuffer;
begin
  urzadzenie.VertexFormat:= CustomVertex.PositionNormalColored.Format;
  bufor:= VertexBuffer.Create(typeof(CustomVertex.PositionNormalColored),
48, urzadzenie, Usage.WriteOnly, CustomVertex.PositionNormalColored.Format, Pool.Default);
  WypelnijBuforWierzch(bufor);
  Result:= bufor;
end;

procedure TWinForm.WypelnijBuforWierzch(var bufor: VertexBuffer);
var
   wierzch : Array[0..47] of CustomVertex.PositionNormalColored;
   strumien: GraphicsStream;
   i,k     : integer;
   tetraedr: Array [0..3] of Vector3;
   normalne: Array [0..3] of Vector3;
   kolory  : Array [0..3] of integer;
   offset  : integer;
begin
  strumien:=  bufor.Lock(0, 0, LockFlags.None);

  tetraedr[0].x:= Math.Sqrt(3)/3.0;
  tetraedr[0].y:= 0;
  tetraedr[0].z:=-Math.Sqrt(6)/12.0;

  tetraedr[1].x:=-Math.Sqrt(3)/6.0;
  tetraedr[1].y:= 0.5;
  tetraedr[1].z:=-Math.Sqrt(6)/12.0;

  tetraedr[2].x:=-Math.Sqrt(3)/6.0;
  tetraedr[2].y:=-0.5;
  tetraedr[2].z:=-Math.Sqrt(6)/12.0;

  tetraedr[3].x:= 0;
  tetraedr[3].y:= 0;
  tetraedr[3].z:= Math.Sqrt(6)/4.0;

  normalne[0]:= Vector3.Cross(tetraedr[2]-tetraedr[0],tetraedr[1]-tetraedr[2]);
  normalne[1]:= Vector3.Cross(tetraedr[2]-tetraedr[1],tetraedr[3]-tetraedr[2]);
  normalne[2]:= Vector3.Cross(tetraedr[2]-tetraedr[3],tetraedr[0]-tetraedr[2]);
  normalne[3]:= Vector3.Cross(tetraedr[0]-tetraedr[3],tetraedr[1]-tetraedr[3]);

  for i:=0 to 3 do normalne[i].Normalize;

  kolory[0]:= Color.Red.ToArgb();
  kolory[1]:= Color.Green.ToArgb();
  kolory[2]:= Color.Blue.ToArgb();
  kolory[3]:= Color.Yellow.ToArgb();

  for i:=0 to 3 do
  begin
    tetraedr[i].z:= tetraedr[i].z-1.0;
  end;

  offset:=0;
  for k:=1 to 4 do
  begin
    wierzch[0+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[0], normalne[0], kolory[0]);
    wierzch[1+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[2], normalne[0], kolory[2]);
    wierzch[2+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[1], normalne[0], kolory[1]);

    wierzch[3+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[1], normalne[1], kolory[1]);
    wierzch[4+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[2], normalne[1], kolory[2]);
    wierzch[5+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[3], normalne[1], kolory[3]);

    wierzch[6+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[3], normalne[2], kolory[3]);
    wierzch[7+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[2], normalne[2], kolory[2]);
    wierzch[8+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[0], normalne[2], kolory[0]);

    wierzch[9+offset] := CustomVertex.PositionNormalColored.Create(tetraedr[3], normalne[3], kolory[3]);
    wierzch[10+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[0], normalne[3], kolory[0]);
    wierzch[11+offset]:= CustomVertex.PositionNormalColored.Create(tetraedr[1], normalne[3], kolory[1]);
    offset:=offset+12;

    for i:=0 to 3 do
    begin
      tetraedr[i].z:= tetraedr[i].z+0.5;
    end;
  end;
  strumien.Write(wierzch);
  bufor.Unlock;
end;

procedure TWinForm.UstawMacierze;
var angle: real;
begin
  angle:= Geometry.DegreeToRadian(Environment.TickCount *360.0/10000.0);
  urzadzenie.Transform.World:= Matrix.RotationYawPitchRoll(angle, angle, angle);
  urzadzenie.Transform.View:= Matrix.LookAtLH(Vector3.Create(0.0, 0.0, -3.0),
    Vector3.Create(0, 0, 0), Vector3.Create(0, 1, 0));
  urzadzenie.Transform.Projection:= Matrix.PerspectiveFovLH(
    Geometry.DegreeToRadian(30.0), 1.0, 1.0, 100.0);
end;

procedure TWinForm.UstawSwiatla;
begin
  urzadzenie.Lights[0].Diffuse  := Color.White;
  urzadzenie.Lights[0].&Type    := LightType.Directional;
  urzadzenie.Lights[0].Direction:= Vector3.Create(0, 0, 1);
  urzadzenie.Lights[0].Update();
  urzadzenie.Lights[0].Enabled  := true;
end;

end.
