unit VertexArray;

interface

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

const
  VERTEX_MASK           = $00000001;
  COLOR0_MASK           = $00000002;
  COLOR1_MASK           = $00000004;
  NORMAL_MASK           = $00000008;
  TEXCOORD_MASK         = $00000010;
  EDGEFLAG_MASK         = $00000020;
  FOGCOORD_MASK         = $00000040;

  STANDARD_MASK         = VERTEX_MASK or COLOR0_MASK or NORMAL_MASK;
  TEXTURED_MASK         = STANDARD_MASK or TEXCOORD_MASK;
  TANGENTSPACE_MASK     = TEXTURED_MASK or COLOR1_MASK;
  FULL_MASK             = VERTEX_MASK or COLOR0_MASK or COLOR1_MASK or
                          NORMAL_MASK or TEXCOORD_MASK or EDGEFLAG_MASK or
                          FOGCOORD_MASK;

  STATIC_MODE           = $00000001;
  DYNAMIC_MODE          = $00000002;

type
  PVertex = ^TVertex;
  TVertex = TVector4;
  PVertexArrayType = ^TVertexArrayType;
  TVertexArrayType = array[0..$FFFFFF] of TVertex;
  PColor = ^TColor;
  TColor = TVector4;
  PColorArrayType = ^TColorArrayType;
  TColorArrayType = array[0..$FFFFFF] of TColor;
  PNormal = ^TNormal;
  TNormal = TVector3;
  PNormalArrayType = ^TNormalArrayType;
  TNormalArrayType = array[0..$FFFFFF] of TNormal;
  PTexCoord = ^TTexCoord;
  TTexCoord = TVector4;
  PTexCoordArrayType = ^TTexCoordArrayType;
  TTexCoordArrayType = array[0..$FFFFFF] of TTexCoord;
  PEdgeFlag = ^TEdgeFlag;
  TEdgeFlag = GLubyte;
  PEdgeFlagArrayType = ^TEdgeFlagArrayType;
  TEdgeFlagArrayType = array[0..$FFFFFF] of TEdgeFlag;
  PFogCoord = ^TFogCoord;
  TFogCoord = GLfloat;
  PFogCoordArrayType = ^TFogCoordArrayType;
  TFogCoordArrayType = array[0..$FFFFFF] of TFogCoord;
  PIndex = ^TIndex;
  TIndex = cardinal;
  PIndexArrayType = ^TIndexArrayType;
  TIndexArrayType = array[0..$FFFFFF] of TIndex;

  PLookupTable = ^TLookupTable;
  TLookupTable = array[0..$FFFFFF] of cardinal;

  TVertexArray = class
  protected
    VertexOffset        : cardinal;
    VertexSize          : cardinal;
    Color0Offset        : cardinal;
    Color0Size          : cardinal;
    Color1Offset        : cardinal;
    Color1Size          : cardinal;
    NormalOffset        : cardinal;
    NormalSize          : cardinal;
    TexCoordOffset      : array[0..31] of cardinal;
    TexCoordSize        : array[0..31] of cardinal;
    EdgeFlagOffset      : cardinal;
    EdgeFlagSize        : cardinal;
    FogCoordOffset      : cardinal;
    FogCoordSize        : cardinal;
    TotalVertexSize     : cardinal;
    TotalIndexSize      : cardinal;
    VertexPointer       : cardinal;
    IndexPointer        : cardinal;
    Initialized         : boolean;

    NrVertex            : cardinal;
    FreeVertex          : cardinal;
    NrVertexBlock       : cardinal;
    VertexLookup        : PLookupTable;
    NrVertexSuperBlock  : cardinal;
    VertexSuperLookup   : PLookupTable;
    NrIndex             : cardinal;
    FreeIndex           : cardinal;
    NrIndexBlock        : cardinal;
    IndexLookup         : PLookupTable;
    NrIndexSuperBlock   : cardinal;
    IndexSuperLookup    : PLookupTable;

    FBufferMode         : cardinal;
    function FindNextFreeVertex(a: cardinal): cardinal; virtual;
    function FindNextFreeIndex(a: cardinal): cardinal; virtual;
    procedure InitPool; virtual;
    procedure FreePool; virtual;
  public
    Vertex              : PVertexArrayType;
    Color0              : PColorArrayType;
    Color1              : PColorArrayType;
    Normal              : PNormalArrayType;
    TexCoord            : array[0..31] of PTexCoordArrayType;
    EdgeFlag            : PEdgeFlagArrayType;
    FogCoord            : PFogCoordArrayType;
    Index               : PIndexArrayType;
    constructor Create; virtual;
    destructor Destroy; override;
    procedure VertexArray(size: cardinal); virtual;
    procedure Color0Array(size: cardinal); virtual;
    procedure Color1Array(size: cardinal); virtual;
    procedure NormalArray(size: cardinal); virtual;
    procedure TexCoordArray(tex, size: cardinal); virtual;
    procedure EdgeFlagArray(size: cardinal); virtual;
    procedure FogCoordArray(size: cardinal); virtual;
    procedure IndexArray(size: cardinal); virtual;
    procedure QuickArrays(numver, numidx, numtex, mask: cardinal); virtual;
    procedure Init; virtual;
    procedure Lock; virtual;
    procedure Unlock; virtual;
    function AllocVertex(num: cardinal): cardinal; virtual;
    procedure DeallocVertex(ptr, num: cardinal); virtual;
    function AllocIndex(num: cardinal): cardinal; virtual;
    procedure DeallocIndex(ptr, num: cardinal); virtual;
    procedure Render(mode, num, base: cardinal); virtual;
    property BufferMode: cardinal read FBufferMode write FBufferMode;
  end;

implementation

constructor TVertexArray.Create;
var
  i: cardinal;
begin
  inherited Create;

  if not Load_GL_EXT_vertex_array then
    raise Exception.Create('GL_EXT_vertex_array required!');

  TotalVertexSize       := 0;
  VertexSize            := 0;
  Color0Size            := 0;
  Color1Size            := 0;
  NormalSize            := 0;
  for i := 0 to 31 do
    TexCoordSize[i] := 0;
  EdgeFlagSize          := 0;
  FogCoordSize          := 0;
  TotalIndexSize        := 0;
  Initialized           := false;
end;

destructor TVertexArray.Destroy;
var
  i: cardinal;
begin
  if Initialized then
  begin
    if VertexSize > 0 then
    begin
      glDisableClientState(GL_VERTEX_ARRAY);
    end;
    if Color0Size > 0 then
    begin
      glDisableClientState(GL_COLOR_ARRAY);
    end;
    if Color1Size > 0 then
    begin
      glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
    end;
    if NormalSize > 0 then
    begin
      glDisableClientState(GL_NORMAL_ARRAY);
    end;
    for i := 0 to 31 do
      if TexCoordSize[i] > 0 then
      begin
        glClientActiveTexture(GL_TEXTURE0 + i);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      end;
    if EdgeFlagSize > 0 then
    begin
      glDisableClientState(GL_EDGE_FLAG_ARRAY);
    end;
    if FogCoordSize > 0 then
    begin
      glDisableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
    end;
    if TotalIndexSize > 0 then
    begin
      glDisableClientState(GL_INDEX_ARRAY);
    end;
    FreeMem(pointer(VertexPointer), TotalVertexSize);
    FreeMem(pointer(IndexPointer), TotalIndexSize);

    FreePool;
  end;

  inherited Destroy;
end;

procedure TVertexArray.VertexArray;
begin
  if (not Initialized) and (VertexSize = 0) then
  begin
    size                := size * 16;
    VertexOffset        := TotalVertexSize;
    VertexSize          := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.VertexArray: Unable to redefine vertex array size');
end;

procedure TVertexArray.Color0Array;
begin
  if (not Initialized) and (Color0Size = 0) then
  begin
    size                := size * 16;
    Color0Offset        := TotalVertexSize;
    Color0Size          := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.Color0Array: Unable to redefine primary color array size');
end;

procedure TVertexArray.Color1Array;
begin
  if not Load_GL_EXT_secondary_color then
    raise Exception.Create('GL_EXT_secondary_color required!');
  if (not Initialized) and (Color1Size = 0) then
  begin
    size                := size * 16;
    Color1Offset        := TotalVertexSize;
    Color1Size          := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.Color1Array: Unable to redefine secondary color array size');
end;

procedure TVertexArray.NormalArray;
begin
  if (not Initialized) and (NormalSize = 0) then
  begin
    size                := size * 12;
    NormalOffset        := TotalVertexSize;
    NormalSize          := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.NormalArray: Unable to redefine normal array size');
end;

procedure TVertexArray.TexCoordArray;
begin
  if (not Initialized) and (TexCoordSize[tex] = 0) then
  begin
    size                := size * 16;
    TexCoordOffset[tex] := TotalVertexSize;
    TexCoordSize[tex]   := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create('TVertexArray.TexCoordArray: ' +
    'Unable to redefine texture coordinate array size');
end;

procedure TVertexArray.EdgeFlagArray;
begin
  if (not Initialized) and (EdgeFlagSize = 0) then
  begin
    EdgeFlagOffset      := TotalVertexSize;
    EdgeFlagSize        := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.EdgeFlagArray: Unable to redefine edge flag array size');
end;

procedure TVertexArray.FogCoordArray;
begin
  if not Load_GL_EXT_fog_coord then
    raise Exception.Create('GL_EXT_fog_coord required!');
  if (not Initialized) and (FogCoordSize = 0) then
  begin
    size                := size * 4;
    FogCoordOffset      := TotalVertexSize;
    FogCoordSize        := size;
    TotalVertexSize     := TotalVertexSize + size;
  end else raise Exception.Create(
    'TVertexArray.FogCoordArray: Unable to redefine fog coordinate array size');
end;

procedure TVertexArray.IndexArray;
begin
  if not Initialized then
  begin
    TotalIndexSize      := size * 4;
  end else raise Exception.Create(
    'TVertexArray.IndexArray: Unable to resize index array after init');
end;

procedure TVertexArray.QuickArrays;
var
  i: cardinal;
begin
  if mask and VERTEX_MASK > 0 then VertexArray(numver);
  if mask and COLOR0_MASK > 0 then Color0Array(numver);
  if mask and COLOR1_MASK > 0 then Color1Array(numver);
  if mask and NORMAL_MASK > 0 then NormalArray(numver);
  if mask and TEXCOORD_MASK > 0 then
    for i := 0 to numtex-1 do
      TexCoordArray(i, numver);
  if mask and EDGEFLAG_MASK > 0 then EdgeFlagArray(numver);
  if mask and FOGCOORD_MASK > 0 then FogCoordArray(numver);
  if numidx > 0 then IndexArray(numidx);
end;

procedure TVertexArray.Init;
var
  i: cardinal;
begin
  GetMem(pointer(VertexPointer), TotalVertexSize);
  GetMem(pointer(IndexPointer), TotalIndexSize);
  if VertexSize > 0 then
  begin
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(4, GL_FLOAT, 0, pointer(VertexPointer + VertexOffset));
  end;
  if Color0Size > 0 then
  begin
    glEnableClientState(GL_COLOR_ARRAY);
    glColorPointer(4, GL_FLOAT, 0, pointer(VertexPointer + Color0Offset));
  end;
  if Color1Size > 0 then
  begin
    glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
    glSecondaryColorPointerEXT(4, GL_FLOAT, 0, pointer(VertexPointer + Color1Offset));
  end;
  if NormalSize > 0 then
  begin
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, 0, pointer(VertexPointer + NormalOffset));
  end;
  for i := 0 to 31 do
    if TexCoordSize[i] > 0 then
    begin
      glClientActiveTexture(GL_TEXTURE0 + i);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glTexCoordPointer(4, GL_FLOAT, 0, pointer(VertexPointer + TexCoordOffset[i]));
    end;
  if EdgeFlagSize > 0 then
  begin
    glEnableClientState(GL_EDGE_FLAG_ARRAY);
    glEdgeFlagPointer(0, pointer(VertexPointer + EdgeFlagOffset));
  end;
  if FogCoordSize > 0 then
  begin
    glEnableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
    glFogCoordPointerEXT(GL_FLOAT, 0, pointer(VertexPointer + FogCoordOffset));
  end;
  if TotalIndexSize > 0 then
  begin
    glEnableClientState(GL_INDEX_ARRAY);
    glIndexPointer(GL_INT, 0, pointer(IndexPointer));
  end;
  Vertex                := pointer(VertexPointer + VertexOffset);
  Color0                := pointer(VertexPointer + Color0Offset);
  Color1                := pointer(VertexPointer + Color1Offset);
  Normal                := pointer(VertexPointer + NormalOffset);
  for i := 0 to 31 do
    TexCoord[i]         := pointer(VertexPointer + TexCoordOffset[i]);
  EdgeFlag              := pointer(VertexPointer + EdgeFlagOffset);
  FogCoord              := pointer(VertexPointer + FogCoordOffset);
  Index                 := pointer(IndexPointer);

  InitPool;

  Initialized           := true;
end;

procedure TVertexArray.Lock;
begin
end;

procedure TVertexArray.Unlock;
begin
end;

procedure TVertexArray.InitPool;
begin
{ initialize vertex super-block and sub-block buffers }
  NrVertex              := VertexSize div 16;
  FreeVertex            := NrVertex;
  NrVertexBlock         := (NrVertex + 31) div 32;
  GetMem(VertexLookup, NrVertexBlock * 4);
  FillChar(VertexLookup^, NrVertexBlock * 4, 0);
  NrVertexSuperBlock    := (NrVertexBlock + 1023) div 1024;
  GetMem(VertexSuperLookup, NrVertexSuperBlock * 4);
  FillChar(VertexSuperLookup^, NrVertexSuperBlock * 4, 0);
{ initialize index super-block and sub-block buffers }
  NrIndex               := TotalIndexSize div 4;
  FreeIndex             := NrIndex;
  NrIndexBlock          := (NrIndex + 31) div 32;
  GetMem(IndexLookup, NrIndexBlock * 4);
  FillChar(IndexLookup^, NrIndexBlock * 4, 0);
  NrIndexSuperBlock     := (NrIndexBlock + 1023) div 1024;
  GetMem(IndexSuperLookup, NrIndexSuperBlock * 4);
  FillChar(IndexSuperLookup^, NrIndexSuperBlock * 4, 0);
end;

procedure TVertexArray.FreePool;
begin
  FreeMem(VertexLookup, NrVertexBlock * 4);
  FreeMem(VertexSuperLookup, NrVertexSuperBlock * 4);
  FreeMem(IndexLookup, NrIndexBlock * 4);
  FreeMem(IndexSuperLookup, NrIndexSuperBlock * 4);
end;

function TVertexArray.FindNextFreeVertex;
var
  i, x: cardinal;
begin
{ track in which super-block is the free vertex }
  x := 0;
  i := a div 32768;
  while VertexSuperLookup[i] = $FFFFFFFF do
    inc(i);
{ track in which bit of the super-block is the free vertex }
  if i = a div 32768 then i := a div 1024
                     else begin
                            i := i * 32; x := 1;
                          end;
  while (VertexSuperLookup[i div 32] and (1 shl (i mod 32))) > 0 do
    inc(i);
{ track in which block is the free vertex }
  if (x = 0) and (i = a div 1024) then i := a div 32
                                  else begin
                                         i := i * 32; x := 1;
                                       end;
  while (VertexLookup[i] = $FFFFFFFF) do
    inc(i);
  if (x = 0) and (i = a div 32) then i := a
                                else i := i * 32;
  while (VertexLookup[i div 32] and (1 shl (i mod 32))) > 0 do
    inc(i);
  result := i;
end;

function TVertexArray.AllocVertex;
var
  addr, n, p, i, j: cardinal;
begin
  addr := 0; n := 0; p := 0;
  if (Num > FreeVertex) then Exception.Create(
    'TVertexHeap.AllocVertex: out of vertex memory');
  while n <> Num do
  begin
{ find first free vertex }
    addr := FindNextFreeVertex(p);
    p := addr + 1;
    n := 1;
{ search for <Num> continuous free vertices }
    while (n <> Num) and
          (VertexLookup[p div 32] and (1 shl (p mod 32)) = 0) and
          (p <> NrVertex) do
    begin
      inc(p); inc(n);
    end;
    if p >= NrVertex then Exception.Create(
      'TVertexHeap.AllocVertex: out of vertex memory');
  end;
  p := addr + n;
  i := addr;
  while i < p do
  begin
{ if it ocupies a full super-block, let set it and it's respective blocks full }
    if (i mod 32768 = 0) and (i + 32767 < p) then
    begin
      VertexSuperLookup[i div 32768] := $FFFFFFFF;
      for j := (i div 32) to ((i div 32) + 1023) do
        VertexLookup[j] := $FFFFFFFF;
      i := i + 32768;
    end else
{ if it ocupies a super-block bit, let set it and it's respective blocks full }
    if (i mod 1024 = 0) and (i + 1023 < p) then
    begin
      VertexSuperLookup[i div 32768] := VertexSuperLookup[i div 32768] or
        (1 shl ((i div 1024) mod 32));
      for j := (i div 32) to ((i div 32) + 31) do
        VertexLookup[j] := $FFFFFFFF;
      i := i + 1024;
    end else
{ if it ocupies a full block, let set it full }
    if (i mod 32 = 0) and (i + 31 < p) then
    begin
      VertexLookup[i div 32] := $FFFFFFFF; i := i + 32;
    end else
{ if it ocupies a block bit, let set it full }
    begin
      VertexLookup[i div 32] := VertexLookup[i div 32] or (1 shl (i mod 32));
      inc(i);
    end;
  end;
  FreeVertex := FreeVertex - Num;
  result := addr;
end;

procedure TVertexArray.DeallocVertex;
var
  addr, n, i, j, p: cardinal;
begin
  addr := Ptr;
  n := Num;
  p := addr + n;
  i := addr;
  while i < p do
  begin
{ if it ocupies a full super-block, let set it and it's respective blocks empty}
    if (i mod 32768 = 0) and (i + 32767 < p) then
    begin
      VertexSuperLookup[i div 32768] := 0;
      for j := (i div 32) to ((i div 32) + 1023) do
        VertexLookup[j] := 0;
      i := i + 32768;
    end else
{ if it ocupies a super-block bit, let set it and it's respective blocks empty }
    if (i mod 1024 = 0) and (i + 1023 < p) then
    begin
      VertexSuperLookup[i div 32768] := VertexSuperLookup[i div 32768] and
        ($FFFFFFFF - (1 shl ((i div 1024) mod 32)));
      for j := (i div 32) to ((i div 32) + 31) do
        VertexLookup[j] := 0;
      i := i + 1024;
    end else
{ if it ocupies a full block, let set it empty }
    if (i mod 32 = 0) and (i + 31 < p) then
    begin
      VertexLookup[i div 32] := 0; i := i + 32;
    end else
{ if it ocupies a block bit, let set it empty }
    begin
      VertexLookup[i div 32] := VertexLookup[i div 32] and
        ($FFFFFFFF - (1 shl (i mod 32)));
      inc(i);
    end;
  end;
  FreeVertex := FreeVertex + Num;
end;

function TVertexArray.FindNextFreeIndex;
var
  i, x: cardinal;
begin
{ track in which super-block is the free Index }
  x := 0;
  i := a div 32768;
  while IndexSuperLookup[i] = $FFFFFFFF do
    inc(i);
{ track in which bit of the super-block is the free Index }
  if i = a div 32768 then i := a div 1024
                     else begin
                            i := i * 32; x := 1;
                          end;
  while (IndexSuperLookup[i div 32] and (1 shl (i mod 32))) > 0 do
    inc(i);
{ track in which block is the free Index }
  if (x = 0) and (i = a div 1024) then i := a div 32
                                  else begin
                                         i := i * 32; x := 1;
                                       end;
  while (IndexLookup[i] = $FFFFFFFF) do
    inc(i);
  if (x = 0) and (i = a div 32) then i := a
                                else i := i * 32;
  while (IndexLookup[i div 32] and (1 shl (i mod 32))) > 0 do
    inc(i);
  result := i;
end;

function TVertexArray.AllocIndex;
var
  addr, n, p, i, j: cardinal;
begin
  addr := 0; n := 0; p := 0;
  if (Num > FreeIndex) then Exception.Create(
    'TVertexHeap.AllocIndex: out of index memory');
  while n <> Num do
  begin
{ find first free Index }
    addr := FindNextFreeIndex(p);
    p := addr + 1;
    n := 1;
{ search for <Num> continuous free vertices }
    while (n <> Num) and
          (IndexLookup[p div 32] and (1 shl (p mod 32)) = 0) and
          (p <> NrIndex) do
    begin
      inc(p); inc(n);
    end;
    if p >= NrIndex then Exception.Create(
      'TVertexHeap.AllocIndex: out of index memory');
  end;
  p := addr + n;
  i := addr;
  while i < p do
  begin
{ if it ocupies a full super-block, let set it and it's respective blocks full }
    if (i mod 32768 = 0) and (i + 32767 < p) then
    begin
      IndexSuperLookup[i div 32768] := $FFFFFFFF;
      for j := (i div 32) to ((i div 32) + 1023) do
        IndexLookup[j] := $FFFFFFFF;
      i := i + 32768;
    end else
{ if it ocupies a super-block bit, let set it and it's respective blocks full }
    if (i mod 1024 = 0) and (i + 1023 < p) then
    begin
      IndexSuperLookup[i div 32768] := IndexSuperLookup[i div 32768] or
        (1 shl ((i div 1024) mod 32));
      for j := (i div 32) to ((i div 32) + 31) do
        IndexLookup[j] := $FFFFFFFF;
      i := i + 1024;
    end else
{ if it ocupies a full block, let set it full }
    if (i mod 32 = 0) and (i + 31 < p) then
    begin
      IndexLookup[i div 32] := $FFFFFFFF; i := i + 32;
    end else
{ if it ocupies a block bit, let set it full }
    begin
      IndexLookup[i div 32] := IndexLookup[i div 32] or (1 shl (i mod 32));
      inc(i);
    end;
  end;
  FreeIndex := FreeIndex - Num;
  result := addr;
end;

procedure TVertexArray.DeallocIndex;
var
  addr, n, i, j, p: cardinal;
begin
  addr := Ptr;
  n := Num;
  p := addr + n;
  i := addr;
  while i < p do
  begin
{ if it ocupies a full super-block, let set it and it's respective blocks empty}
    if (i mod 32768 = 0) and (i + 32767 < p) then
    begin
      IndexSuperLookup[i div 32768] := 0;
      for j := (i div 32) to ((i div 32) + 1023) do
        IndexLookup[j] := 0;
      i := i + 32768;
    end else
{ if it ocupies a super-block bit, let set it and it's respective blocks empty }
    if (i mod 1024 = 0) and (i + 1023 < p) then
    begin
      IndexSuperLookup[i div 32768] := IndexSuperLookup[i div 32768] and
        ($FFFFFFFF - (1 shl ((i div 1024) mod 32)));
      for j := (i div 32) to ((i div 32) + 31) do
        IndexLookup[j] := 0;
      i := i + 1024;
    end else
{ if it ocupies a full block, let set it empty }
    if (i mod 32 = 0) and (i + 31 < p) then
    begin
      IndexLookup[i div 32] := 0; i := i + 32;
    end else
{ if it ocupies a block bit, let set it empty }
    begin
      IndexLookup[i div 32] := IndexLookup[i div 32] and
        ($FFFFFFFF - (1 shl (i mod 32)));
      inc(i);
    end;
  end;
  FreeIndex := FreeIndex + Num;
end;

procedure TVertexArray.Render;
begin
  glDrawElements(mode, num, GL_UNSIGNED_INT, @Index[base]);
end;

end.
