//{{{ TVertexBuffer private part
function TVertexBuffer.FindAndCreateLayer(LayerId: PtrUInt;
                                          out Layer: PVertexLayer): Boolean;
var
  I: LongInt;
begin
  if LayerId < Length(TLayersArray) then begin
    if FLayersArray = nil then begin
      New(FLayersArray);
      for I := 0 to High(TLayersArray) do begin
        FLayersArray^[I].FId := I;
        FLayersArray^[I].FType := -1;
      end;
    end;
    Layer := @FLayersArray^[LayerId];
    Exit(Layer^.FType <> -1);
  end else begin
    for I := 0 to High(FLayersMap) do begin
      if FLayersMap[I].FId = LayerId then begin
        Layer := @FLayersMap[I];
        Exit(True);
      end;
    end;
    SetLength(FLayersMap, Length(FLayersMap) + 1);
    Layer := @FLayersMap[High(FLayersMap)];
    Layer^.FId := LayerId;
    Exit(False);
  end;
end;

function TVertexBuffer.GetVertexSize(_Type: LongInt): LongInt;
begin
  case _Type of
    1: Result := SizeOf(TVec2i);
    2: Result := SizeOf(TVec2f);
    3: Result := SizeOf(TVec3f);
  else
    Result := 0;
  end;
end;

procedure TVertexBuffer.SetVerticesType(NewType: LongInt);
var
  OldSize, NewSize: LongInt;
begin
  if NewType = 0 then begin
    if FVertexType <> 0 then begin
      FVertices.Done;
    end;
  end else begin
    if FVertexType = 0 then begin
      FVertices.Init(FCount * GetVertexSize(NewType));
    end else begin
      OldSize := GetVertexSize(FVertexType);
      NewSize := GetVertexSize(NewType);
      if NewSize > OldSize then begin
        FVertices.Done;
        FVertices.Init(FCount * NewSize);
      end;
    end;
  end;
  FVertexType := NewType;
end;

function TVertexBuffer.GetColorSize(_Type: LongInt): LongInt;
begin
  case _Type of
    1: Result := SizeOf(TColor);
    2: Result := SizeOf(TVec4f);
  else
    Result := 0;
  end;
end;

procedure TVertexBuffer.SetColorsType(NewType: LongInt);
var
  OldSize, NewSize: LongInt;
begin
  if NewType = 0 then begin
    if FColorType <> 0 then begin
      FColors.Done;
    end;
  end else begin
    if FColorType = 0 then begin
      FColors.Init(FCount * GetColorSize(NewType));
    end else begin
      OldSize := GetColorSize(FColorType);
      NewSize := GetColorSize(NewType);
      if NewSize > OldSize then begin
        FColors.Done;
        FColors.Init(FCount * NewSize);
      end;
    end;
  end;
  FColorType := NewType;
end;

function TVertexBuffer.GetNormalSize(_Type: LongInt): LongInt;
begin
  case _Type of
    1: Result := SizeOf(TVec3f);
  else
    Result := 0;
  end;
end;

procedure TVertexBuffer.SetNormalsType(NewType: LongInt);
var
  OldSize, NewSize: LongInt;
begin
  if NewType = 0 then begin
    if FNormalType <> 0 then begin
      FNormals.Done;
    end;
  end else begin
    if FNormalType = 0 then begin
      FNormals.Init(FCount * GetNormalSize(NewType));
    end else begin
      OldSize := GetNormalSize(FNormalType);
      NewSize := GetNormalSize(NewType);
      if NewSize > OldSize then begin
        FNormals.Done;
        FNormals.Init(FCount * NewSize);
      end;
    end;
  end;
  FNormalType := NewType;
end;

function TVertexBuffer.GetTexCoordSize(_Type: LongInt): LongInt;
begin
  case _Type of
    1: Result := SizeOf(TVec2f);
    2: Result := SizeOf(TVec3f);
  else
    Result := 0;
  end;
end;

procedure TVertexBuffer.SetTexCoordsType(NewType: LongInt);
var
  OldSize, NewSize: LongInt;
begin
  if NewType = 0 then begin
    if FTexCoordType <> 0 then begin
      FTexCoords.Done;
    end;
  end else begin
    if FTexCoordType = 0 then begin
      FTexCoords.Init(FCount * GetTexCoordSize(NewType));
    end else begin
      OldSize := GetTexCoordSize(FTexCoordType);
      NewSize := GetTexCoordSize(NewType);
      if NewSize > OldSize then begin
        FTexCoords.Done;
        FTexCoords.Init(FCount * NewSize);
      end;
    end;
  end;
  FTexCoordType := NewType;
end;

procedure TVertexBuffer.EnableLayer(Layer: PVertexLayer);
begin
  Log('TODO TVertexBuffer.EnableLayer');
end;

procedure TVertexBuffer.DisableLayer(Layer: PVertexLayer);
begin
  Log('TODO TVertexBuffer.DisableLayer');
end;

procedure TVertexBuffer.Enable;
begin
  Log('TODO TVertexBuffer.Enable');
end;

procedure TVertexBuffer.Disable;
begin
  Log('TODO TVertexBuffer.Disable');
end;

//}}}
//{{{ TVertexBuffer get layers
procedure TVertexBuffer.DeleteVertices;
begin
  SetVerticesType(0);
end;

function TVertexBuffer.Vertices2i: PArrayOfVec2i;
begin
  if FVertexType <> 1 then
    SetVerticesType(1);
  Result := FVertices.Data;
end;

function TVertexBuffer.Vertices2f: PArrayOfVec2f;
begin
  if FVertexType <> 2 then
    SetVerticesType(2);
  Result := FVertices.Data;
end;

function TVertexBuffer.Vertices3f: PArrayOfVec3f;
begin
  if FVertexType <> 3 then
    SetVerticesType(3);
  Result := FVertices.Data;
end;

procedure TVertexBuffer.DeleteColors;
begin
  SetColorsType(0);
end;

function TVertexBuffer.Colors4ub: PArrayOfVec4ub;
begin
  if FColorType <> 1 then
    SetColorsType(1);
  Result := FColors.Data;
end;

function TVertexBuffer.Colors4f: PArrayOfVec4f;
begin
  if FColorType <> 2 then
    SetColorsType(2);
  Result := FColors.Data;
end;

procedure TVertexBuffer.DeleteNormals;
begin
  SetNormalsType(0);
end;

function TVertexBuffer.Normals: PArrayOfVec3f;
begin
  if FNormalType <> 1 then
    SetNormalsType(1);
  Result := FNormals.Data;
end;

procedure TVertexBuffer.DeleteTexCoords;
begin
  SetTexCoordsType(0);
end;

function TVertexBuffer.TexCoords2f: PArrayOfVec2f;
begin
  if FTexCoordType <> 1 then
    SetTexCoordsType(1);
  Result := FTexCoords.Data;
end;

function TVertexBuffer.TexCoords3f: PArrayOfVec3f;
begin
  if FTexCoordType <> 2 then
    SetTexCoordsType(2);
  Result := FTexCoords.Data;
end;

procedure TVertexBuffer.SetLayer(LayerId: PtrUInt;
                   Components: PtrUInt;
                   _Type: PtrUInt;
                   ElementSize: LongInt;
                   Data: Pointer);
var
  Layer: PVertexLayer;
begin
  if FindAndCreateLayer(LayerId, Layer) then
    Layer^.FBuffer.Done;
  Layer^.FComponents := Components;
  Layer^.FType := _Type;
  Layer^.FElementSize := ElementSize;
  Layer^.FBuffer.Init(Data);
end;

procedure TVertexBuffer.SetLayer(LayerId: PtrUInt;
                  const P: array of TVec2f);
begin
  Log('TODO TVertexBuffer.SetLayer');
end;

procedure TVertexBuffer.SetLayer(LayerId: PtrUInt;
                  const P: array of TVec3f);
begin
  Log('TODO TVertexBuffer.SetLayer');
end;

procedure TVertexBuffer.SetLayer(LayerId: PtrUInt;
                  const P: array of TVec4f);
begin
  Log('TODO TVertexBuffer.SetLayer');
end;

function TVertexBuffer.GetLayer(LayerId: PtrUInt;
               Components: PtrUInt;
               _Type: PtrUInt;
               ElementSize: LongInt): Pointer;
var
  Layer: PVertexLayer;
begin
  if FindAndCreateLayer(LayerId, Layer) then begin
    if (Layer^.FComponents <> Components) or (Layer^.FType <> _Type) then begin
      Layer^.FBuffer.Done;
      Layer^.FComponents := Components;
      Layer^.FType := _Type;
      Layer^.FElementSize := ElementSize;
      Layer^.FBuffer.Init(FCount * Layer^.FElementSize);
    end;
  end else begin
    Layer^.FComponents := Components;
    Layer^.FType := _Type;
    Layer^.FElementSize := ElementSize;
    Layer^.FBuffer.Init(FCount * Layer^.FElementSize);
  end;
  Result := Layer^.FBuffer.Data;
end;

function TVertexBuffer.Layer2f(LayerId: PtrUInt): PArrayOfVec2f;
begin
  Log('TODO TVertexBuffer.SetLayer2f');
  Exit(nil);
end;

function TVertexBuffer.Layer3f(LayerId: PtrUInt): PArrayOfVec3f;
begin
  Log('TODO TVertexBuffer.SetLayer3f');
  Exit(nil);
end;

function TVertexBuffer.Layer4f(LayerId: PtrUInt): PArrayOfVec4f;
begin
  Log('TODO TVertexBuffer.SetLayer4f');
  Exit(nil);
end;

procedure TVertexBuffer.DeleteLayer(LayerId: PtrUInt);
var
  I: LongInt;
  Layer: PVertexLayer;
begin
  if LayerId < Length(TLayersArray) then begin
    if FLayersArray = nil then
      Exit;
    Layer := @FLayersArray^[LayerId];
    if Layer^.FType <> -1 then begin
      Layer^.FBuffer.Done;
      Layer^.FType := -1;
      Exit;
    end;
  end else begin
    for I := 0 to High(FLayersMap) do begin
      if FLayersMap[I].FId = LayerId then begin
        Layer := @FLayersMap[I];
        Layer^.FBuffer.Done;
        Layer^ := FLayersMap[High(FLayersMap)];
        SetLength(FLayersMap, Length(FLayersMap) - 1);
        Exit;
      end;
    end;
  end;
end;
//}}}
//{{{ TVertexBuffer rendering
procedure TVertexBuffer.DrawPoints;
begin
  Log('TODO TVertexBuffer.DrawPoints');
end;

{$IFNDEF ANDROID}
procedure TVertexBuffer.DrawQuads;
begin
  Log('TODO TVertexBuffer.DrawQuads');
end;
{$ENDIF}

procedure TVertexBuffer.DrawTriangles;
begin
  Log('TODO TVertexBuffer.DrawTriangles');
end;

procedure TVertexBuffer.DrawLineLoop;
begin
  Log('TODO TVertexBuffer.DrawLineLoop');
end;

procedure TVertexBuffer.DrawLines;
begin
  Log('TODO TVertexBuffer.DrawLines');
end;

procedure TVertexBuffer.DrawPolygon;
begin
  Log('TODO TVertexBuffer.DrawPolygon');
end;

procedure TVertexBuffer.DrawPoints(const Indices: TIndexBuffer);
begin
  Log('TODO TVertexBuffer.DrawPoints');
end;

{$IFNDEF ANDROID}
procedure TVertexBuffer.DrawQuads(const Indices: TIndexBuffer);
begin
  Log('TODO TVertexBuffer.DrawQuads');
end;
{$ENDIF}

procedure TVertexBuffer.DrawTriangles(const Indices: TIndexBuffer);
begin
  Log('TODO TVertexBuffer.DrawTrinalges');
end;
//}}}
