unit ex2;

{$mode objfpc}{$H+}

interface

{ This example draws a box. It comes with different flavors :
  - e2lNone : without lighting but with water
  - e2lLightness : with lighting and water
  - e2lColored : with two lights of different colors, but without water
 
 In this example, faces are textured. Each texture is generated with utexture unit. 
 Because we want to have a shiny effect on the box, we need to create different material.
 The parameter of CreateMaterial is the exponent of the specular light, which is the
 concentration of the reflected beam. The lamps are not shiny, but we must see some of the 
 light through them, that's why the LightThroughFactor is set to a small non zero number.
 
 The lighting normals are the direction considered to be orthogonal to the surface. The box
 uses lnFace, which means that each face is considered to be flat. On the contrary, lamps
 are rounded, so their lighting normals are lnVertex, which means that the surface is considered
 to be rounded between faces, using vertices as a reference. The example 3 show the difference
 between these modes.
}

uses
  Classes, SysUtils, BGRAScene3D, BGRABitmap, BGRABitmapTypes
  {$IFNDEF NO_OPENGL_SURFACE}, BGRAOpenGL3D{$ENDIF};

type
  TExample2Lighting = (e2lNone,e2lLightness,e2lColored);

  { TExample2 }

  TExample2 = class({$IFNDEF NO_OPENGL_SURFACE}TBGLScene3D{$ELSE}TBGRAScene3D{$ENDIF})
  private
    water,wood,vWood: TBGRABitmap;
    box,ground,light1,light2: IBGRAObject3D;
    alpha: integer;
    cury: single;
    FLighting: TExample2Lighting;
    procedure CreateScene;
    procedure ApplyTexCoord(face: IBGRAFace3D; Times: integer = 1);
    procedure SetLighting(AValue: TExample2Lighting);
  public
    constructor Create(ALighting: TExample2Lighting);
    procedure Elapse;
    destructor Destroy; override;
    property Lighting: TExample2Lighting read FLighting write SetLighting;
  end;

implementation

uses utexture;

const texSize = 256;

{ TExample2 }

constructor TExample2.Create(ALighting: TExample2Lighting);
begin
  inherited Create;

  //create textures
  water := CreateWaterTexture(texSize,texSize);
  vWood := CreateVerticalWoodTexture(texSize,texSize);
  wood := CreateWoodTexture(texSize,texSize);

  FLighting:= ALighting;
  CreateScene;
end;

procedure TExample2.Elapse;
var dy: single;
begin
  if light1 <> nil then light1.MainPart.RotateYDeg(1,False);
  if light2 <> nil then light2.MainPart.RotateYDeg(-1.3,False);
  if ground <> nil then
  begin
    dy := cos(alpha*Pi/180)*0.05;
    cury += dy;
    ground.MainPart.Translate(0,dy,0,False);
    ViewPoint := Point3D(ViewPoint.x,-40+cury,ViewPoint.z);
    LookAt(Point3D(0,cury,0),Point3D(0,-1,0));
    inc(alpha);
    if alpha = 360 then alpha := 0;
  end;
end;

procedure TExample2.CreateScene;
var
  base,v: array of IBGRAVertex3D;
  lamp,shiny: IBGRAMaterial3D;
begin
  Clear;

  shiny := CreateMaterial(500);
  lamp := CreateMaterial;
  lamp.LightThroughFactor := 0.01;

  //create wooden box
  box := CreateObject(vWood);
  with box do
  begin
    v := MainPart.Add([-1,-1,-1, 1,-1,-1, 1,1,-1, -1,1,-1,
                       -1,-1,+1, 1,-1,+1, 1,1,+1, -1,1,+1]);

    ApplyTexCoord(AddFace([v[0],v[1],v[2],v[3]]));
    ApplyTexCoord(AddFace([v[4],v[5],v[1],v[0]],wood));
    ApplyTexCoord(AddFace([v[5],v[4],v[7],v[6]]));
    ApplyTexCoord(AddFace([v[3],v[2],v[6],v[7]],wood));
    ApplyTexCoord(AddFace([v[1],v[5],v[6],v[2]]));
    ApplyTexCoord(AddFace([v[4],v[0],v[3],v[7]]));

    MainPart.Scale(20);
  end;

  DefaultLightingNormal:= lnFace;

  if Lighting = e2lColored then
  begin
    ViewPoint := Point3D(0,0,-150);
    AmbiantLightColor := BGRA(192,192,192);
    box.Material := shiny;

    //lights
    light1 := CreateHalfSphere(10, BGRA(255,128,0), 8,8);
    with light1 do
    begin
      AddPointLight(MainPart.Add(0,0,-5),60,BGRA(255,128,0),0);
      MainPart.Translate(-100,-50,0);
      MainPart.LookAt(Point3D(0,0,0),Point3D(0,-1,0));
      Material := lamp;
      LightingNormal := lnVertex;
    end;
    light2 := CreateHalfSphere(10, BGRA(0,128,255), 8,8);
    with light2 do
    begin
      AddPointLight(MainPart.Add(0,0,-5),100,BGRA(0,128,255),0);
      MainPart.Translate(50,0,-100);
      MainPart.LookAt(Point3D(0,0,0),Point3D(0,-1,0));
      Material := lamp;
      LightingNormal := lnVertex;
    end;
  end else
  begin
    //create ground
    ground := CreateObject(water);
    if Lighting = e2lLightness then
    begin
      with ground do
      begin
        base := MainPart.Add([-50,0,-50, -50,0,50, 50,0,50, 50,0,-50]);
        ApplyTexCoord(AddFace(base,True),2);
      end;
      ViewPoint := Point3D(-40,-40,-100);
      AmbiantLightness := 0.25;
      with CreateObject do
        AddPointLight(MainPart.Add(-100,-80,0),100,1.25, -0.15);
    end else
    begin
      AmbiantLightness := 1;
      with ground do
      begin
        base := MainPart.Add([-50,0,-50, -50,0,50, 50,0,50, 50,0,-50]);
        MainPart.Scale(2);
        ApplyTexCoord(AddFace(base,True),2);
      end;
      ViewPoint := Point3D(0,-40,-120);
    end;
    RenderingOptions.PerspectiveMode:= pmZBuffer;
  end;

  RenderingOptions.TextureInterpolation := false;
end;

procedure TExample2.ApplyTexCoord(face: IBGRAFace3D; Times: integer);
begin
  with face do
  begin
    TexCoord[0] := PointF(0,0);
    TexCoord[1] := PointF(texSize*Times-1,0);
    TexCoord[2] := PointF(texSize*Times-1,texSize*Times-1);
    TexCoord[3] := PointF(0,texSize*Times-1);
  end;
end;

procedure TExample2.SetLighting(AValue: TExample2Lighting);
begin
  if FLighting=AValue then Exit;
  FLighting:=AValue;
  CreateScene;
end;

destructor TExample2.Destroy;
begin
  water.free;
  wood.free;
  vWood.free;
  inherited Destroy;
end;

end.

