unit winmain;

interface

uses
  SysUtils, Types, Classes, Variants,
{$ifdef linux}
  Libc,  QGraphics, QControls,QForms, QDialogs,QExtCtrls,QTypes, QStdCtrls, QButtons, QComCtrls,
{$else}
  Windows, Messages,Graphics, Controls, Forms,Dialogs, ExtCtrls, StdCtrls, Spin,
{$endif}
  IGLWidget, MiniGL, IGLTime;
type
  uint    = cardinal;

  TForm1 = class(TForm)
    Panel1: TPanel;
    inp_triangles: TSpinEdit;
    grp_modes: TRadioGroup;
    Timer1: TTimer;
    Timer2: TTimer;
    lbl_info1: TLabel;
    lbl_info2: TLabel;
    lbl_info3: TLabel;
    lbl_message: TLabel;
    Button1: TButton;
    Label1: TLabel;
    SpinEdit1: TSpinEdit;
    Label2: TLabel;
    Bevel1: TBevel;
    Timer3: TTimer;
{****************************************************************************************
    YOU CANT ALLOW DELPHI OR KYLIX TO DELETE THISE DEFFS BELOW                          *
    THEY WILL ASK YOU ABOUT THAT!!!!!!!!!!!!!                                          *}

    {$ifdef win32}
    btnw_Quit: TButton;
    btnw_set: TButton;
    {$endif}
    {$ifdef linux}
    btn_set: TBitBtn;
    btn_Quit: TBitBtn;
    Image1: TImage;
    Bevel2: TBevel;
    {$endif}
{************************************************************************************}
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure Reshape(Sender: TObject);
    procedure startrefresh(Sender: TObject);
    procedure btn_QuitClick(Sender: TObject);
    procedure setNewValue(Sender: TObject);
    procedure tm2errors(Sender: TObject);
    procedure performancelabels(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure SpinEdit1Change(Sender: TObject);
    procedure SpinExit(Sender: TObject);
  private
  { Private declarations }
    PrecTimer : IGLTimer;
    PrecTimer2 : IGLTimer;
//Becouse of windows multitasking wich is a joke
//we cant change label.caption (that is on the same windows as gl)
//every gl resfresh becouse this will stop opengl!!!!!
//if you dont belive try....
//Linux doesn't have such problems
//so we will use sparestreings
//anyway changing captions on the same windows as glpanel affects opengl
//performance on Windows98, and NT too !!! but NOT ON LINUX
        sparecaption : string;
        sparecaption2 : string;
  public
    { Public declarations }

    //This Object is responsible for connection betwen Qt and OpenGL
    ObjectCount : integer;
    GLO : TIGLGraphicContext;
    procedure BuildLists(value : integer);
  end;
type
  // Vertex type for vertex array.
  TVertex = packed record
    Nx, Ny, Nz: Single;
    Vx, Vy, Vz: Single;
  end;

const
  IM        = 0;       // Immediate mode: GL_TRIANGLES with 3*n vertices.
  STRIP     = 1;       // Triangle strip: GL_TRIANGLE+STRIP with 2+n vertices.
  IMLIST    = 2;       // Immediate mode compiled into a display list.
  STRIPLIST = 3;       // Triangle strip compiled into a display list.
  VASTRIP   = 4;       // Triangle strip precalculated to a vertex array.
var
  Form1: TForm1;
  listIM, listStrip: GLenum;
  va: array of TVertex;
  angle: Integer = 0;

procedure RenderMesh(count: Integer; mode: Integer);


implementation
{$ifdef linux}
    {$R *.xfm}
{$else}
    {$R *.dfm}
{$endif}

procedure TForm1.FormCreate(Sender: TObject);
begin
    PrecTimer := IGLTimer.Create;
    PrecTimer2 := IGLTimer.Create;
    ObjectCount := inp_triangles.Value;
    GLO :=TIGLGraphicContext.Create(Panel1);
    GLO.IGLFormat :=    glf_DoubleBuffer
                     or glf_DirectRendering
                     or glf_DepthBuffer
                     or glf_Rgba
                     or glf_NoOverlay
                     or glf_NoAlphaChannel
                     or glf_NoStereoBuffers
                     or glf_NoAccumBuffer
                     or glf_NoStencilBuffer;
    with GLO.bits do begin
        cColorBits      :=8; //Minimal of bits we can accept
        cDepthBits      :=8;
        cAlphaBits      :=1;
    end;
    {$ifdef linux}
    glo.major_glx:=0;
    glo.minor_glx:=0;
    {$endif}
    GLO.GLSetup;
    GLO.MakeCurrent;
    {$ifdef linux}
    Caption:=Caption +' : Glx ver. ' +IntToStr(GLO.major_glx)+'.'+IntToStr(GLO.major_glx);
    {$endif}
    glEnable(GL_DEPTH_TEST);

    BuildLists(ObjectCount);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity;
    gluPerspective(60, 1, 1, 10);
    glMatrixMode(GL_MODELVIEW);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    // Enable the vertex arrays.
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    RenderMesh(ObjectCount, VASTRIP);
    glNormalPointer(GL_FLOAT, 24, @va[0].Nx);
    glVertexPointer(3, GL_FLOAT, 24, @va[0].Vx);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin

    gluPerspective(60,                              //field of view y-dricetion
                    panel1.Width/panel1.Height,     //aspect
                    -10,                              //near
                    100);                            //far
    PrecTimer.Start;

    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glLoadIdentity;
    glTranslatef(0, 0, -2.5);
    glRotatef(angle, 1, 2, -3);

  case Grp_Modes.ItemIndex of
    0: RenderMesh(ObjectCount, IM);
    1: RenderMesh(ObjectCount, STRIP);
    { The following three are by far the fastest, because they can render the
      mesh with a single procedure call. }
    2: glCallList(listIM);
    3: glCallList(listStrip);
    4: glDrawArrays(GL_TRIANGLE_STRIP, 0, ObjectCount+2);
  end;

  PrecTimer.Stop;
  sparecaption:=Format('Transfer modes -- %.2f fps', [1000000/PrecTimer.USecElapsed]);
  sparecaption2:=Format('1 frame in %5d usec',[PrecTimer.USecElapsed]);
  GLO.SwapActiveBuffers;


end;

procedure TForm1.Reshape(Sender: TObject);
begin
    GLO.SetViewPort;
    GLO.SwapActiveBuffers;


end;

procedure TForm1.startrefresh(Sender: TObject);
begin
    angle := (angle + 1) mod 360;
    Paint;
end;

procedure TForm1.btn_QuitClick(Sender: TObject);
begin
    GLO.Destroy;
    Halt(1)

end;

procedure TForm1.setNewValue(Sender: TObject);
begin
  // When the polygon count is changed, update the lists and the VA.
  ObjectCount:=inp_triangles.Value;
  BuildLists(ObjectCount);
  RenderMesh(ObjectCount, VASTRIP);
  glNormalPointer(GL_FLOAT, 24, @va[0].Nx);
  glVertexPointer(3, GL_FLOAT, 24, @va[0].Vx);

end;

procedure TForm1.tm2errors(Sender: TObject);
begin
//    lbl_CLK_TCK.Caption:=IntToStr(CLK_TCK);
    lbl_message.Caption:=PrecTimer.ErrorMessage;

end;
procedure RenderMesh(count: Integer; mode: Integer);
var
  i: Integer;
  a: Single;
  sina  : single;
  cosa  : single;
  invcount : single;
begin
  // Create the mesh, using the supplied mode (IM, STRIP, etc.)
  if mode = STRIP then
  begin
    glBegin(GL_TRIANGLE_STRIP);
    invcount :=1 / count;
    for i := 0 to count + 1 do
    begin
        a := i*pi*2*invcount;
        sina:=sin(a);
        cosa:=cos(a);
        glNormal3f(cosa, 0, sina);
        if Odd(i) then glVertex3f(cosa, -0.5, sina)
        else glVertex3f(cosa, 0.5, sina);
    end;
    glEnd;
  end
  else if mode = IM then
  begin
    glBegin(GL_TRIANGLES);
    invcount :=1 / count;
    for i := 0 to count + 1 do
    begin
        a := i*pi*2*invcount;
        sina:=sin(a);
        cosa:=cos(a);
        glNormal3f(cosa, 0, sina);
        if Odd(i) then glVertex3f(cosa, -0.5, sina)
        else glVertex3f(cosa, 0.5, sina);

        a := (i+1)*pi*2*invcount;
        sina:=sin(a);
        cosa:=cos(a);
        glNormal3f(cosa, 0, sina);
        if not Odd(i) then glVertex3f(cosa, -0.5, sina)
        else glVertex3f(cosa, 0.5, sina);

        a := (i+2)*pi*2*invcount;
        sina:=sin(a);
        cosa:=cos(a);
        glNormal3f(cosa, 0, sina);
        if Odd(i) then glVertex3f(cosa, -0.5, sina)
        else glVertex3f(cosa, 0.5, sina);
      end;
    glEnd;
  end
  else if mode = VASTRIP then
  begin
    SetLength(va, count+2);
    for i := 0 to count + 1 do
    begin
      a := i*pi*2/count;
      sina:=sin(a);
      cosa:=cos(a);
      va[i].Nx := cosa;
      va[i].Ny := 0;
      va[i].Nz := sina;
      va[i].Vx := cosa;
      if Odd(i) then va[i].Vy := -0.5
      else va[i].Vy := 0.5;
      va[i].Vz := sina;
    end;
  end;
end;
procedure TForm1.BuildLists(value : integer);
begin

  // Build the display lists.
  if glIsList(listIM) = GL_TRUE then glDeleteLists(listIM, 1);
  if glIsList(listStrip) = GL_TRUE then glDeleteLists(listStrip, 1);

  listIM := glGenLists(1);
  listStrip := glGenLists(1);
  PrecTimer2.Start;
  glNewList(listIM, GL_COMPILE);
    RenderMesh(Value, IM);
  glEndList;
  glNewList(listStrip, GL_COMPILE);
    RenderMesh(Value, STRIP);
  glEndList;
  PrecTimer2.Stop;
  lbl_info2.Caption:=Format('Generation took %10d usec = %5d sec and %5d usec',[PrecTimer2.USecElapsed,PrecTimer2.SecElapsed,
                    PrecTimer2.USecElapsed-PrecTimer2.SecElapsed*1000000]);

end;

procedure TForm1.performancelabels(Sender: TObject);
begin
    lbl_info1.Caption :=sparecaption;
    lbl_info3.Caption :=sparecaption2;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
        Timer3.Enabled:=Not(Timer3.Enabled);
end;
procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
        timer3.Interval:=round(1000/SpinEdit1.Value);
end;
procedure TForm1.SpinExit(Sender: TObject);
begin
        timer3.Interval:=round(1000/SpinEdit1.Value);
end;

end.
