unit texture1;

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);
    procedure FormDestroy(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}

const
  Level=0;
  Border=0;
  ColorComps=3;

type
  TRGB=packed record
    r,g,b: byte;
  end;

  TWrap=array[0..0]of TRGB;

var
  sBulk,
  tBulk: GLsizei;
  bulk: pointer;

function ReadBitmap(const FilePath:string;var sWidth,tHeight:GLsizei): pointer;
const
  szh=SizeOf(TBitmapFileHeader);
  szi=SizeOf(TBitmapInfoHeader);
var
  bmpfile: file;
  bfh: TBitmapFileHeader;
  bmi: TBitmapInfoHeader;
  t: byte;
  x,
  size: integer;
begin
  assignFile(bmpfile,FilePath);
  reset(bmpfile,1);
  size := FileSize(bmpfile)-szh-szi;
  blockread(bmpfile,bfh,szh);
  if Bfh.bfType<>$4D42 then
    raise EInvalidGraphic.Create('Invalid Bitmap');
  blockread(bmpfile,bmi,szi);
  with bmi do
  begin
    sWidth := biWidth;
    tHeight := biHeight;
  end;
  getmem(result,size);
  blockread(bmpfile,result^,size);
  for x := 0 to sWidth*tHeight-1 do
  with TWrap(result^)[x] do
  begin
    t := r;
    r := b;
    b := t;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
  bulk := ReadBitmap('fig13-07.bmp',sBulk,tBulk);

  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: GLfloat;
begin
  angl := angl+rot;
  theta := angl*pi180;
  wx := wx-tran*sin(theta);
  wz := wz+tran*cos(theta);
end;

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

procedure TForm1.Opening;
begin
  glEnable(GL_TEXTURE_2D);

  glTexImage2D(GL_TEXTURE_2D,Level,ColorComps,sBulk,tBulk,Border,
    GL_RGB,GL_UNSIGNED_BYTE,bulk);

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

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

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

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

  glDisable(GL_TEXTURE_2D);

end;


procedure Tform1.FormDestroy(Sender: TObject);
begin
  FreeMem(bulk);
end;

end.
  