unit Frost.RenderEngine;

interface

uses
  Frost.GameObjects,
  OpenGl,  
  _Geometry,
  Frost.GL;
     
type
TCamera = class (TComponent)
  private              
    FView: TMatrix4;
    FOrder: Byte;
    procedure Use;
  public
    procedure OnStart; override;
    procedure OnUpdate(const delta: Double); override;
    procedure OnDestroy; override; 
    property Order: Byte read FOrder write FOrder;
    property View: TMatrix4 read FView;
end;

TRenderLayer = class
  protected
    FOrder: Byte;      
    procedure Render; virtual;
  public
    property Order: Byte read FOrder write FOrder;
  end;

TRenderEngine = class sealed
    class var FInstance: TRenderEngine;
  private
    FCameraCount,
    FMaxCameras: Integer;
    FCamera: array of TCamera;
    FLayerCount,
    FMaxLayers: Integer;
    FLayer: array of TRenderLayer;
  public
    constructor Create(Camera: TCamera);
    destructor Destroy; override;
    procedure AddCamera(Camera: TCamera);
    procedure AddLayer(Layer: TRenderLayer);
    procedure Render;
  end;

implementation

{$REGION 'TCamera'}
procedure TCamera.Use;
begin
  glLoadIdentity;
  glMultMatrixf(@FView);
end;

procedure TCamera.OnStart;
begin                    
  FView := IDENTITY_MATRIX4;
  if (TRenderEngine.FInstance <> nil) then
    TRenderEngine.FInstance.AddCamera(Self);  
end;

procedure TCamera.OnUpdate(const delta: Double);
begin
  FView := Matrix4(GameObject.Rotation.Transpose, -GameObject.Rotation * GameObject.Position);
end;

procedure TCamera.OnDestroy;
begin

end;
{$ENDREGION}

{$REGION 'TLayer'}
procedure TRenderLayer.Render;
begin

end;
{$ENDREGION}

{$REGION 'TRenderEngine'}
constructor TRenderEngine.Create(Camera: TCamera);
begin
  FInstance := Self;
  FCameraCount := 0;
  FMaxCameras := 0;
  FLayerCount := 0;
  FMaxLayers := 0;
  if Camera <> nil then
  begin
    AddCamera(Camera);
  end;
end;

destructor TRenderEngine.Destroy;
begin
  inherited;
end;

procedure TRenderEngine.AddCamera(Camera: TCamera);
begin
  if Camera = nil then
    Exit;
  if (FCameraCount >= FMaxCameras) then
    begin
      FMaxCameras := FMaxCameras + 1;
      SetLength(FCamera, FMaxCameras + 1);
    end;
  FCamera[FCameraCount] := Camera;
  Camera.Order := FCameraCount;
  Inc(FCameraCount);
end;

procedure TRenderEngine.AddLayer(Layer: TRenderLayer);
begin
  if Layer = nil then
    Exit;
  if (FLayerCount >= FMaxLayers) then
  begin
    FMaxLayers := FMaxLayers + 1;
    SetLength(FLayer, FMaxLayers + 1);
  end;
  FLayer[FLayerCount] := Layer;
  Layer.Order := FLayerCount;
  Inc(FLayerCount);
end;

procedure TRenderEngine.Render;
var
  i, j: Word;
begin             
  gl.BeginRender;
  for i := 0 to FCameraCount - 1 do
    if FCamera[i] <> nil then
    begin                
      FCamera[i].Use;
      for j := 0 to FLayerCount - 1 do
        if FLayer[j] <> nil then
        begin    
          FLayer[j].Render;    
        end;
    end;
  gl.EndRender;
end;    
{$ENDREGION}

end.
