unit detect1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  cOpenGL, Material, light, Transfrm, OpenGL, MMSystem;

type
  TForm1 = class(TForm)
    OpenGL1: TOpenGL;
    TransformLight: TTransform;
    TransformFloor: TTransform;
    TransformCube: TTransform;
    Light1: TLight;
    MaterialLight: TMaterial;
    MaterialFloor: TMaterial;
    MaterialCube: TMaterial;
    TransformCyl: TTransform;
    MaterialCyl: TMaterial;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure TransformLightPaint(Sender: TObject);
    procedure TransformFloorPaint(Sender: TObject);
    procedure TransformCubePaint(Sender: TObject);
    procedure TransformCylPaint(Sender: TObject);
  private
    angl,
    rspeed,
    speed,
    tran,
    rot,
    wx,
    wz: GLfloat;
    frames,
    elapsed,
    start: integer;
    procedure Idle(Sender:TObject;var Done:boolean);
    procedure Adjust;
    procedure Opening;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  pi180: double=pi/180.0;

implementation

uses Shapes;

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  Application.OnIdle := Idle;
  CylinderBase;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if OpenGL1.Smaller then
    FormPaint(Sender);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  Opening;  

  glRotatef(angl,0.0,1.0,0.0);
  glTranslatef(wx,0.0,wz);

  TransformLight.Apply;
  TransformFloor.Apply;
  TransformCube.Apply;
  TransformCyl.Apply;

  OpenGL1.Swap;
  OpenGL1.ErrorCheck('FormPaint');
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_UP: tran := +speed;
    VK_DOWN: tran := -speed;
    VK_LEFT: rot := -rspeed;
    VK_RIGHT: rot := +rspeed;
    VK_ESCAPE: Close;
    ord('R'): begin
      if ssShift in Shift then
        rspeed := rspeed+0.01
      else begin
        if rspeed>0.01 then
          rspeed := rspeed-0.01;
      end;
    end;
    ord('S'): begin
      if ssShift in Shift then
        speed := speed+0.001
      else begin
        if speed>0.001 then
          speed := speed-0.001;
      end;
    end;
  end; {case}
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  tran := 0.0;
  rot := 0.0;
end;

procedure TForm1.Idle(Sender:TObject;var Done:boolean);
const
  rollover=1000;
  mspersec=1000.0;
begin
  Done := false;
  Adjust;
  inc(frames);
  if frames>=rollover then
  begin
    elapsed := TimeGetTime;
    Caption := Format('fps=%0.1f',[rollover*mspersec/(elapsed-start)]);
    start := elapsed;
    frames := 0;
  end else
    FormPaint(nil);
end;

procedure TForm1.TransformFloorPaint(Sender: TObject);
begin
  MaterialFloor.Apply;
  glBegin(GL_POLYGON);
    glVertex3f(-29.0,0.0,-29.0);
    glVertex3f(-29.0,0.0,+29.0);
    glVertex3f(+29.0,0.0,+29.0);
    glVertex3f(+29.0,0.0,-29.0);
  glEnd;
end;

procedure TForm1.TransformLightPaint(Sender: TObject);
begin
  Light1.Apply;
  MaterialLight.Apply;
  Cube;
end;

procedure TForm1.TransformCubePaint(Sender: TObject);
begin
  MaterialCube.Apply;
  Cube;
end;

procedure TForm1.Adjust;
var
  theta,
  viewerx,
  viewerz,
  deltax,
  deltaz,
  distance,
  savex,
  savez: GLfloat;

function restore: boolean;
begin
  result := true;
  wx := savex;
  wz := savez;
  Caption := 'Bump!'
end;

begin
  angl := angl+rot;
  theta := angl*pi180;
  savex := wx;
  wx := wx-tran*sin(theta);
  savez := wz;
  wz := wz+tran*cos(theta);

  viewerz := -wz;
  viewerx := -wx;
  with TransformCyl do
  begin
    deltax := TranX-viewerx;
    deltaz := TranZ-viewerz;
    distance := sqrt(deltax*deltax+deltaz*deltaz);
    if (distance<2.515) and restore then
      exit;
  end;
  with TransformCube do
  begin
    deltax := TranX-viewerx;
    deltaz := TranZ-viewerz;
    distance := sqrt(deltax*deltax+deltaz*deltaz);
    if (distance<2.67) then
    begin
      if (distance<2.42) and restore then
        exit;
      deltax := TranX+0.4-viewerx;
      deltaz := TranZ+0.4-viewerz;
      distance := sqrt(deltax*deltax+deltaz*deltaz);
      if (distance<2.42) and restore then
        exit;
      deltax := TranX+0.4-viewerx;
      deltaz := TranZ-0.4-viewerx;
      distance := sqrt(deltax*deltax+deltaz*deltaz);
      if (distance<2.42) and restore then
        exit;
      deltax := TranX-0.4-viewerx;
      deltaz := TranZ+0.4-viewerz;
      distance := sqrt(deltax*deltax+deltaz*deltaz);
      if (distance<2.42) and restore then
        exit;
      deltax := TranX-0.4-viewerx;
      deltaz := TranZ-0.4-viewerz;
      distance := sqrt(deltax*deltax+deltaz*deltaz);
      if (distance<2.42) and restore then
        exit;
    end;
  end;
end;


procedure TForm1.TransformCylPaint(Sender: TObject);
begin
  MaterialCyl.Apply;
  Cylinder;
end;

procedure TForm1.Opening;
begin
  glBegin(GL_POLYGON);
    glVertex3f(-1.0,+1.0,-2.0);
    glVertex3f(-1.0,-1.0,-2.0);
    glVertex3f(-0.7,-1.0,-2.0);
    glVertex3f(-0.7,+1.0,-2.0);
  glEnd;

  glBegin(GL_POLYGON);
    glVertex3f(-0.7,+1.0,-2.0);
    glVertex3f(-0.7,+0.7,-2.0);
    glVertex3f(-0.4,+0.7,-2.0);
    glVertex3f(-0.4,+1.0,-2.0);
  glEnd;

  glBegin(GL_POLYGON);
    glVertex3f(+0.7,+1.0,-2.0);
    glVertex3f(+0.7,-1.0,-2.0);
    glVertex3f(+1.0,-1.0,-2.0);
    glVertex3f(+1.0,+1.0,-2.0);
  glEnd;

  glBegin(GL_POLYGON);
    glVertex3f(+0.4,+1.0,-2.0);
    glVertex3f(+0.4,+0.7,-2.0);
    glVertex3f(+0.7,+0.7,-2.0);
    glVertex3f(+0.7,+1.0,-2.0);
  glEnd;
end;

end.
  