unit ScissorBox;

interface

uses Windows, SysUtils, GL, GLu, GLext, WGLext, GLtools;

type
  TScissorRect = record
    x, y, w, h: longint;
  end;

  TScissorBox = class
  protected
    FRect               : array of TScissorRect;
    FDepth              : integer;
    FCurDepth           : integer;
    FDefaultRect        : TScissorRect;
    function GetRect: TScissorRect;
  public
    constructor Create(depth: integer); virtual;
    destructor Destroy; override;
    procedure Enable; virtual;
    procedure Disable; virtual;
    procedure Section(x, y, w, h: longint); virtual;
    procedure CrossSection(x, y, w, h: longint); virtual;
    procedure Default; virtual;
    procedure Push; virtual;
    procedure Pop; virtual;
    property Rect: TScissorRect read GetRect;
  end;

implementation

constructor TScissorBox.Create;
begin
  inherited Create;

  FDepth := depth;
  FCurDepth := 0;

  SetLength(FRect, FDepth);

  glGetIntegerv(GL_SCISSOR_BOX, @FDefaultRect);
  FRect[FCurDepth] := FDefaultRect;
end;

destructor TScissorBox.Destroy;
begin
  SetLength(FRect, 0);

  inherited Destroy;
end;

function TScissorBox.GetRect;
begin
  result := FRect[FCurDepth];
end;

procedure TScissorBox.Enable;
begin
  glEnable(GL_SCISSOR_TEST);
  with FRect[FCurDepth] do
    glScissor(x, y, w, h);
end;

procedure TScissorBox.Disable;
begin
  glDisable(GL_SCISSOR_TEST);
end;

procedure TScissorBox.Section;
begin
  FRect[FCurDepth].x := x;
  FRect[FCurDepth].y := y;
  FRect[FCurDepth].w := w;
  FRect[FCurDepth].h := h;
  glScissor(x, y, w, h);
end;

procedure TScissorBox.CrossSection;
var
  x1, x2, y1, y2: longint;
begin
  x1 := FRect[FCurDepth].x + FRect[FCurDepth].w - 1;
  y1 := FRect[FCurDepth].y + FRect[FCurDepth].h - 1;
  x2 := x + w - 1;
  y2 := y + h - 1;
  if FRect[FCurDepth].x > x then x := FRect[FCurDepth].x;
  if FRect[FCurDepth].y > y then y := FRect[FCurDepth].y;
  if x1 < x2 then x2 := x1;
  if y1 < y2 then y2 := y1;
  w := x2 - x + 1;
  h := y2 - y + 1;
  Section(x, y, w, h);
end;

procedure TScissorBox.Default;
begin
  FRect[FCurDepth] := FDefaultRect;
  with FRect[FCurDepth] do
    glScissor(x, y, w, h);
end;

procedure TScissorBox.Push;
begin
  inc(FCurDepth);
  FRect[FCurDepth] := FRect[FCurDepth-1];
end;

procedure TScissorBox.Pop;
begin
  dec(FCurDepth);
  with FRect[FCurDepth] do
    glScissor(x, y, w, h);
end;

end.
