lazarus/components/tachart/tadraweropengl.pas

809 lines
22 KiB
ObjectPascal

{
*****************************************************************************
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
Authors: Alexander Klenin, Werner Pamler
Notes:
- This unit is not "used" by the TAChart package. In order to find it the
unit should be copied to the project folder or specified with its path
in the uses clause (see demo project).
- If define CHARTGL_USE_LAZFREETYPE is activated in the package options then
the LazFreeType library is used for rendering text. If not, the GLUT library
is used instead. Note that GLUT is not available on every system.
- If LazFreeType does not find the fonts needed call InitFonts at the beginning
of the program and specify the path to the font folder as a parameter.
Several folders can be used if separated by LineEnding codes.
}
unit TADrawerOpenGL;
{$H+}
interface
{$DEFINE CHARTGL_USE_LAZFREETYPE}
uses
Classes, SysUtils, FPCanvas, FPImage,
TAChartUtils, TADrawUtils;
type
{ TOpenGLDrawer }
TOpenGLDrawer = class(TBasicDrawer, IChartDrawer)
strict private
FBrushColor: TFPColor;
FFontColor: TFPColor;
FPenColor: TFPColor;
FPenStyle: TFPPenStyle;
FPenWidth: Integer;
FFontName: String;
FFontSize: Integer;
FFontStyle: Integer;
FFontAngle: Double;
FPos: TPoint;
procedure ChartGLColor(AColor: TFPColor);
procedure ChartGLPenStyle(APenStyle: TFPPenStyle);
procedure InternalPolyline(
const APoints: array of TPoint; AStartIndex, ANumPts, AMode: Integer);
procedure SetBrush(ABrush: TFPCustomBrush);
procedure SetFont(AFont: TFPCustomFont);
procedure SetPen(APen: TFPCustomPen);
strict protected
function GetFontAngle: Double; override;
function SimpleTextExtent(const AText: String): TPoint; override;
procedure SimpleTextOut(AX, AY: Integer; const AText: String); override;
public
constructor Create;
procedure AddToFontOrientation(ADelta: Integer);
procedure ClippingStart;
procedure ClippingStart(const AClipRect: TRect);
procedure ClippingStop;
procedure Ellipse(AX1, AY1, AX2, AY2: Integer);
procedure FillRect(AX1, AY1, AX2, AY2: Integer);
function GetBrushColor: TChartColor;
procedure Line(AX1, AY1, AX2, AY2: Integer);
procedure Line(const AP1, AP2: TPoint);
procedure LineTo(AX, AY: Integer); override;
procedure MoveTo(AX, AY: Integer); override;
procedure Polygon(
const APoints: array of TPoint; AStartIndex, ANumPts: Integer); override;
procedure Polyline(
const APoints: array of TPoint; AStartIndex, ANumPts: Integer);
procedure PrepareSimplePen(AColor: TChartColor);
procedure PutPixel(AX, AY: Integer; AColor: TChartColor); override;
procedure RadialPie(
AX1, AY1, AX2, AY2: Integer;
AStartAngle16Deg, AAngleLength16Deg: Integer);
procedure Rectangle(const ARect: TRect);
procedure Rectangle(AX1, AY1, AX2, AY2: Integer);
procedure ResetFont;
procedure SetAntialiasingMode(AValue: TChartAntialiasingMode);
procedure SetBrushColor(AColor: TChartColor);
procedure SetBrushParams(AStyle: TFPBrushStyle; AColor: TChartColor);
procedure SetPenParams(AStyle: TFPPenStyle; AColor: TChartColor);
procedure SetTransparency(ATransparency: TChartTransparency);
end;
{$IFDEF CHARTGL_USE_LAZFREETYPE}
procedure InitFonts(AFontDir: string = '');
procedure DoneFonts;
{$ENDIF}
implementation
uses
GL, GLu, FileUtil,
{$IFDEF CHARTGL_USE_LAZFREETYPE}
LazFileUtils,
EasyLazFreeType, LazFreeTypeFPImageDrawer, LazFreeTypeFontCollection,
{$ELSE}
Glut,
{$ENDIF}
TAGeometry;
{$IFDEF CHARTGL_USE_LAZFREETYPE}
type
TTextureCacheItem = class
TextureID: Gluint;
TextWidth: Integer;
TextHeight: Integer;
end;
TGLFreeTypeHelper = class
private
FFont: TFreeTypeFont;
FImg: TFPMemoryImage;
FDrawer: TFPImageFreeTypeDrawer;
FTextureCache: TStringList;
protected
function BuildTextureName(AText: String): String;
procedure CreateTexture(AText: String; out ATextWidth, ATextHeight,
ATextureWidth, ATextureHeight: Integer; out ATextureID: GLuint);
function FindTexture(AText: String; out ATextWidth, ATextHeight,
ATextureWidth, ATextureHeight: Integer): GLuint;
public
constructor Create;
destructor Destroy; override;
procedure RenderText(AText: String; Alignments: TFreeTypeAlignments);
procedure SetFont(AFontName: String; AFontSize: Integer;
ABold: Boolean = false; AItalic: Boolean = false;
AUnderline: Boolean = false; AStrikethrough: Boolean = false);
procedure TextExtent(AText: String; out AWidth, AHeight: Integer);
end;
var
FontDirList: TStrings = nil;
GLFreeTypeHelper: TGLFreeTypeHelper = nil;
function NextPowerOf2(n: Integer): Integer;
begin
Result := 1;
while Result < n do
Result := Result * 2;
end;
procedure CreateFontDirList;
var
s: String;
begin
FontDirList := TStringList.Create;
{$IFDEF WINDOWS}
s := SHGetFolderPathUTF8(20); // CSIDL_FONTS = 20
if s <> '' then
FontDirList.Add(s);
{$ENDIF}
{$IFDEF linux}
FontDirList.Add('/usr/share/cups/fonts/');
FontDirList.Add('/usr/share/fonts/truetype/');
FontDirList.Add('/usr/local/lib/X11/fonts/');
FontDirList.Add(GetUserDir + '.fonts/');
{$ENDIF}
end;
procedure InitFonts(AFontDir: String = '');
{ Duplicates functionality in FontCollection.AddFolder in order to be able to
ignore exceptions due to font read errors (occur on Linux Mint with font
NanumMyeongjo.ttf }
procedure AddFolder(AFolder: string);
var
files: TStringList;
i: integer;
begin
AFolder := ExpandFileName(AFolder);
if (length(AFolder) <> 0) and (AFolder[length(AFolder)] <> PathDelim) then
AFolder += PathDelim;
files := TStringList.Create;
FontCollection.BeginUpdate;
try
FindAllFiles(files, AFolder, '*.ttf', true);
files.Sort;
for i := 0 to files.Count-1 do
try
FontCollection.AddFile(files[i]);
except
end;
finally
FontCollection.EndUpdate;
files.Free;
end;
end;
var
i: Integer;
begin
if FontDirList = nil then
CreateFontDirList;
if AFontDir <> '' then
FontDirList.Text := AFontDir;
FontCollection := TFreeTypeFontCollection.Create;
for i:=0 to FontDirList.Count-1 do
AddFolder(FontDirList[i]);
GLFreeTypeHelper := TGLFreeTypeHelper.Create;
end;
procedure DoneFonts;
begin
FreeAndNil(GLFreeTypeHelper);
FreeAndNil(FontDirList);
FreeAndNil(FontCollection);
end;
function LoadFont(AFontName: String; AStyle: TFreeTypeStyles): TFreeTypeFont;
var
familyItem: TCustomFamilyCollectionItem;
fontItem: TCustomFontCollectionItem;
style: String;
begin
Result := nil;
familyItem := FontCollection.Family[AFontName];
if familyItem <> nil then begin
style := '';
if (ftsBold in AStyle) then style := 'Bold';
if (ftsItalic in AStyle) then style := style + ' Italic';
fontItem := familyItem.GetFont(style);
if fontItem <> nil then begin
Result := fontItem.CreateFont;
Result.Style := AStyle;
end;
end;
end;
{ TGLFreeTypeHelper }
constructor TGLFreeTypeHelper.Create;
begin
FImg := TFPMemoryImage.Create(8, 8); // dummy size, will be updated when needed
FDrawer := TFPImageFreeTypeDrawer.Create(FImg);
FTextureCache := TStringList.Create;
FTextureCache.Sorted := true;
end;
destructor TGLFreeTypeHelper.Destroy;
var
i: Integer;
item: TTextureCacheItem;
begin
for i:=0 to FTextureCache.Count-1 do begin
item := TTextureCacheItem(FTextureCache.Objects[i]);
glDeleteTextures(1, @item.TextureID);
item.Free;
end;
FTextureCache.Free;
if FFont <> nil then FFont.Free;
FDrawer.Free;
FImg.Free;
inherited;
end;
{ The texture items are stored in the FTextureCache list and can be identified
by means of their name which is composed of the text and font parameters.
The name of the texture items is calculated here. }
function TGLFreeTypeHelper.BuildTextureName(AText: String): String;
begin
Result := Format('%s|%s|%d|%s', [
AText, FFont.Family, round(FFont.SizeInPoints*100), FFont.StyleAsString
]);
end;
procedure TGLFreeTypeHelper.CreateTexture(AText: String; out ATextWidth, ATextHeight,
ATextureWidth, ATextureHeight: Integer; out ATextureID: GLuint);
var
expanded_data: packed array of byte;
i, j: Integer;
c: TFPColor;
begin
if FFont = nil then
raise Exception.Create('No font selected.');
ATextWidth := round(FFont.TextWidth(AText));
ATextHeight := round(FFont.TextHeight(AText));
ATextureWidth := NextPowerOf2(ATextWidth);
ATextureHeight := NextPowerOf2(ATextHeight);
FImg.SetSize(ATextureWidth, ATextureHeight);
FDrawer.FillPixels(colTransparent);
FDrawer.DrawText(AText, FFont, 0,0, colRed, [ftaLeft, ftaTop]);
SetLength(expanded_data, 2*ATextureWidth * ATextureHeight);
for j:=0 to ATextureHeight-1 do
for i:=0 to ATextureWidth-1 do
begin
expanded_data[2*(i + j*ATextureWidth)] := 255; // Luminosity
if (i > ATextWidth) or (j > ATextHeight) then
expanded_data[2*(i + j*ATextureWidth) + 1] := 0 // Alpha
else begin
c := FImg.Colors[i,j];
expanded_data[2*(i + j*ATextureWidth) + 1] := FImg.Colors[i, j].Alpha shr 8;
end;
end;
// Set up texture parameters
glGenTextures(1, @ATextureID);
glBindTexture(GL_TEXTURE_2D, ATextureID);
// Create the texture
// Note that we are using GL_LUMINANCE_ALPHA to indicate that we are using
// two-channel data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ATextureWidth, ATextureHeight, 0,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, @expanded_data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
end;
{ Finds the texture id for the given text. Returns the texture id and the
size of text and texture. Note that the texture size must be a power of 2 and
thus can be different from the text size. }
function TGLFreeTypeHelper.FindTexture(AText: String;
out ATextWidth, ATextHeight, ATextureWidth, ATextureHeight: Integer): GLuint;
var
idx: Integer;
item: TTextureCacheItem;
txname: String;
begin
txname := BuildTextureName(AText);
idx := FTextureCache.IndexOf(txname);
if idx = -1 then begin
CreateTexture(AText, ATextWidth, ATextHeight, ATextureWidth, ATextureHeight, Result);
item := TTextureCacheItem.Create;
item.TextureID := Result;
item.TextWidth := ATextWidth;
item.TextHeight := ATextHeight;
FTextureCache.AddObject(txname, item);
end else begin
item := TTextureCacheItem(FTextureCache.Objects[idx]);
result := item.TextureID;
ATextWidth := item.TextWidth;
ATextHeight := item.TextHeight;
ATextureWidth := NextPowerOf2(ATextWidth);
ATextureHeight := NextPowerOf2(ATextHeight);
end;
end;
procedure TGLFreeTypeHelper.RenderText(AText: String; Alignments: TFreeTypeAlignments);
var
textureID: GLuint;
w, h: Integer;
w2, h2: Integer;
sx, sy: Double;
dx, dy: Integer;
begin
textureID := FindTexture(AText, w, h, w2, h2);
sx := w / w2;
sy := h / h2;
glMatrixMode(GL_MODELVIEW);
glPushMatrix;
// Note: We don't support ftaJustify)
if (ftaCenter in Alignments) then dx := -w div 2
else if (ftaRight in ALignments) then dx := -w
else dx := 0;
if (ftaVerticalCenter in Alignments) then dy := -h div 2
else if (ftaBottom in Alignments) then dy := -h
else if (ftaBaseline in Alignments) then dy := - h + round(FFont.Descent)
else dy := 0;
glTranslatef(dx, dy, 0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
glBegin(GL_QUADS);
glTexCoord2f(0.0, sy); glVertex2f(0, h);
glTexCoord2f(sx, sy); glVertex2f(w, h);
glTexCoord2f(sx, 0.0); glVertex2f(w, 0);
glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix;
end;
procedure TGLFreeTypeHelper.SetFont(AFontName: String; AFontSize: Integer;
ABold: Boolean = false; AItalic: Boolean = false;
AUnderline: Boolean = false; AStrikethrough: Boolean = false);
var
style: TFreeTypeStyles;
begin
if GLFreeTypeHelper = nil then
raise Exception.Create('InitFonts has not been called.');
style := [];
if ABold then Include(style, ftsBold);
if AItalic then Include(style, ftsItalic);
// Create a new font if not yet loaded
if (FFont = nil) or (FFont.Family <> AFontName) or (FFont.Style <> style) then
begin
FreeAndNil(FFont);
FFont := LoadFont(AFontName, style);
if FFont = nil then
raise Exception.CreateFmt('Font "%s" not found.', [AFontName]);
end;
// Set the requested font attributes.
FFont.SizeInPoints := AFontSize;
FFont.UnderlineDecoration := AUnderline;
FFont.StrikeoutDecoration := AStrikethrough;
FFont.Hinted := true;
FFont.Quality := grqHighQuality;
//FFont.ClearType := true;
end;
{ Returns the width and height of the specified text. If the text already has
been handled with the same font parameters it is stored in the FTextureCache
list. If not, the size is determined from the font. }
procedure TGLFreeTypeHelper.TextExtent(AText: String; out AWidth, AHeight: Integer);
var
txname: String;
idx: Integer;
item: TTextureCacheItem;
textureID: Gluint;
w2, h2: Integer;
begin
txname := BuildTextureName(AText);
idx := FTextureCache.IndexOf(txname);
if idx = -1 then begin
CreateTexture(AText, AWidth, AHeight, w2, h2, textureID);
item := TTextureCacheItem.Create;
item.TextureID := textureID;
item.TextWidth := AWidth;
item.TextHeight := AHeight;
idx := FTextureCache.AddObject(txname, item);
end;
item := TTextureCacheItem(FTextureCache.Objects[idx]);
AWidth := item.TextWidth;
AHeight := item.TextHeight;
end;
{$ENDIF}
{ TOpenGLDrawer }
constructor TOpenGLDrawer.Create;
{$IFDEF CHARTGL_USE_LAZFREETYPE}
begin
inherited;
end;
{$ELSE}
var
CmdCount : Integer;
Cmd : Array of Pchar;
I: Integer;
begin
CmdCount := Paramcount+1;
SetLength(Cmd,CmdCount);
for I := 0 to CmdCount - 1 do
Cmd[I] := PChar(ParamStr(I));
glutInit (@CmdCount,@Cmd);
end;
{$ENDIF}
procedure TOpenGLDrawer.AddToFontOrientation(ADelta: Integer);
begin
FFontAngle := FFontAngle + ADelta / ORIENTATION_UNITS_PER_DEG;
end;
procedure TOpenGLDrawer.ChartGLColor(AColor: TFPColor);
begin
with AColor do
glColor4us(red, green, blue, (255 - FTransparency) shl 8);
end;
procedure TOpenGLDrawer.ChartGLPenStyle(APenStyle: TFPPenStyle);
var
pattern: Word;
begin
case APenStyle of
psClear : pattern := %0000000000000000;
psDot : pattern := %0011001100110011;
psDash : pattern := %0000000011111111;
psDashDot : pattern := %0001100011111111;
psDashDotDot : pattern := %0001101100111111;
else
glDisable(GL_LINE_STIPPLE); // --> psSolid
exit;
// psPattern will render as psSolid because there are differences in
// implementations between fpc and lcl.
// psInsideFrame will render as psSolid - I don't know what this is...
end;
glLineStipple(1, pattern);
glEnable(GL_LINE_STIPPLE);
end;
procedure TOpenGLDrawer.ClippingStart(const AClipRect: TRect);
type
TGLClipPlaneEqn = record A, B, C, D: GLdouble; end;
var
cp: TGLClipPlaneEqn;
begin
cp.A := 1.0;
cp.D := -AClipRect.Left;
glClipPlane(GL_CLIP_PLANE0, @cp);
cp.A := -1.0;
cp.D := AClipRect.Right;
glClipPlane(GL_CLIP_PLANE1, @cp);
cp.A := 0.0;
cp.B := 1.0;
cp.D := -AClipRect.Top;
glClipPlane(GL_CLIP_PLANE2, @cp);
cp.B := -1.0;
cp.D := AClipRect.Bottom;
glClipPlane(GL_CLIP_PLANE3, @cp);
ClippingStart;
end;
procedure TOpenGLDrawer.ClippingStart;
begin
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
end;
procedure TOpenGLDrawer.ClippingStop;
begin
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
end;
procedure TOpenGLDrawer.Ellipse(AX1, AY1, AX2, AY2: Integer);
var
p: TPointArray;
begin
p := TesselateEllipse(Rect(AX1, AY1, AX2, AY2), 4);
Polygon(p, 0, Length(p));
end;
procedure TOpenGLDrawer.FillRect(AX1, AY1, AX2, AY2: Integer);
begin
ChartGLColor(FBrushColor);
glRecti(AX1, AY1, AX2, AY2);
end;
function TOpenGLDrawer.GetBrushColor: TChartColor;
begin
Result := FPColorToChartColor(FBrushColor);
end;
function TOpenGLDrawer.GetFontAngle: Double;
begin
Result := 0.0;
end;
procedure TOpenGLDrawer.InternalPolyline(
const APoints: array of TPoint; AStartIndex, ANumPts, AMode: Integer);
var
i: Integer;
begin
if FPenStyle = psClear then exit;
ChartGLColor(FPenColor);
glBegin(AMode);
for i := AStartIndex to AStartIndex + ANumPts - 1 do
glVertex2iv(@APoints[i]);
glEnd();
end;
procedure TOpenGLDrawer.Line(AX1, AY1, AX2, AY2: Integer);
begin
if FPenStyle = psClear then exit;
glBegin(GL_LINES);
ChartGLColor(FPenColor);
glVertex2i(AX1, AY1);
glVertex2i(AX2, AY2);
glEnd();
end;
procedure TOpenGLDrawer.Line(const AP1, AP2: TPoint);
begin
Line(AP1.X, AP1.Y, AP2.X, AP2.Y);
end;
procedure TOpenGLDrawer.LineTo(AX, AY: Integer);
begin
Line(FPos.X, FPos.Y, AX, AY);
end;
procedure TOpenGLDrawer.MoveTo(AX, AY: Integer);
begin
FPos := Point(AX, AY);
end;
procedure TOpenGLDrawer.Polygon(
const APoints: array of TPoint; AStartIndex, ANumPts: Integer);
var
i: Integer;
begin
glBegin(GL_POLYGON);
ChartGLColor(FBrushColor);
for i := AStartIndex to AStartIndex + ANumPts - 1 do
glVertex2iv(@APoints[i]);
glEnd();
InternalPolyline(APoints, AStartIndex, ANumPts, GL_LINE_LOOP);
end;
procedure TOpenGLDrawer.Polyline(
const APoints: array of TPoint; AStartIndex, ANumPts: Integer);
begin
InternalPolyline(APoints, AStartIndex, ANumPts, GL_LINE_STRIP);
end;
procedure TOpenGLDrawer.PrepareSimplePen(AColor: TChartColor);
begin
FPenWidth := 1;
FPenColor := FChartColorToFPColorFunc(AColor);
FPenStyle := psSolid;
end;
procedure TOpenGLDrawer.PutPixel(AX, AY: Integer; AColor: TChartColor);
begin
ChartGLColor(FChartColorToFPColorFunc(AColor));
glBegin(GL_POINTS);
glVertex2i(AX, AY);
glEnd;
end;
procedure TOpenGLDrawer.RadialPie(
AX1, AY1, AX2, AY2: Integer; AStartAngle16Deg, AAngleLength16Deg: Integer);
var
e: TEllipse;
p: TPointArray;
begin
e.InitBoundingBox(AX1, AY1, AX2, AY2);
p := e.TesselateRadialPie(
Deg16ToRad(AStartAngle16Deg), Deg16ToRad(AAngleLength16Deg), 4);
Polygon(p, 0, Length(p));
end;
procedure TOpenGLDrawer.Rectangle(AX1, AY1, AX2, AY2: Integer);
begin
ChartGLColor(FBrushColor);
glRecti(AX1, AY1, AX2, AY2);
if FPenStyle = psClear then exit;
ChartGLColor(FPenColor);
glBegin(GL_LINE_LOOP);
glVertex2i(AX1, AY1);
glVertex2i(AX2, AY1);
glVertex2i(AX2, AY2);
glVertex2i(AX1, AY2);
glEnd();
end;
procedure TOpenGLDrawer.Rectangle(const ARect: TRect);
begin
Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
end;
procedure TOpenGLDrawer.ResetFont;
begin
end;
procedure TOpenGLDrawer.SetAntialiasingMode(AValue: TChartAntialiasingMode);
begin
case AValue of
amOn: begin
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
end;
amOff: begin
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);
end;
end;
end;
procedure TOpenGLDrawer.SetBrush(ABrush: TFPCustomBrush);
begin
FBrushColor := ABrush.FPColor;
end;
procedure TOpenGLDrawer.SetBrushColor(AColor: TChartColor);
begin
FBrushColor := FChartColorToFPColorFunc(AColor);
end;
procedure TOpenGLDrawer.SetBrushParams(
AStyle: TFPBrushStyle; AColor: TChartColor);
begin
SetBrushColor(AColor);
Unused(AStyle);
end;
procedure TOpenGLDrawer.SetFont(AFont: TFPCustomFont);
begin
FFontName := AFont.Name;
if Sametext(FFontName, 'default') then FFontName := 'Arial';
FFontSize := AFont.Size;
if FFontSize = 0 then FFontSize := 10;
FFontStyle := 0;
if AFont.Bold then inc(FFontStyle, 1);
if AFont.Italic then inc(FFontStyle, 2);
if AFont.Underline then inc(FFontStyle, 4);
if AFont.Strikethrough then inc(FFontStyle, 8);
FFontColor := AFont.FPColor;
{$IFDEF CHARTGL_USE_LAZFREETYPE}
FFontAngle := FGetFontOrientationFunc(AFont) / ORIENTATION_UNITS_PER_DEG;
GLFreeTypeHelper.SetFont(FFontName, FFontSize,
AFont.Bold, AFont.Italic, AFont.Underline, AFont.Strikethrough);
{$ENDIF}
end;
procedure TOpenGLDrawer.SetPen(APen: TFPCustomPen);
begin
FPenWidth := APen.Width;
FPenColor := APen.FPColor;
FPenStyle := APen.Style;
glLineWidth(FPenWidth);
ChartGLPenStyle(FPenStyle);
end;
procedure TOpenGLDrawer.SetPenParams(AStyle: TFPPenStyle; AColor: TChartColor);
begin
FPenStyle := AStyle;
FPenColor := FChartColorToFPColorFunc(AColor);
ChartGLPenStyle(AStyle);
end;
procedure TOpenGLDrawer.SetTransparency(ATransparency: TChartTransparency);
begin
inherited;
if FTransparency > 0 then begin
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
end
else
glDisable(GL_BLEND);
end;
{$IFDEF CHARTGL_USE_LAZFREETYPE}
function TOpenGLDrawer.SimpleTextExtent(const AText: String): TPoint;
begin
GLFreeTypeHelper.TextExtent(AText, Result.X, Result.Y);
end;
procedure TOpenGLDrawer.SimpleTextOut(AX, AY: Integer; const AText: String);
begin
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
ChartGLColor(FFontColor);
glMatrixMode(GL_MODELVIEW);
glPushMatrix;
glTranslatef(AX, AY, 0);
glRotatef(-FFontAngle, 0, 0, 1);
GLFreeTypeHelper.RenderText(AText, [ftaLeft, ftaTop]);
glPopMatrix;
end;
{$ELSE}
function TOpenGLDrawer.SimpleTextExtent(const AText: String): TPoint;
const
F_WIDTH = 8;
F_HEIGHT = 13;
begin
Result := Point(F_WIDTH * Length(AText), F_HEIGHT);
end;
procedure TOpenGLDrawer.SimpleTextOut(AX, AY: Integer; const AText: String);
const
X_OFFSET = 0;
Y_OFFSET = 10;
var
i: Integer;
begin
ChartGLColor(FFontColor);
glRasterPos2i(AX + X_OFFSET, AY + Y_OFFSET);
for i := 1 to Length(AText) do
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, Ord(AText[i]));
end;
{$ENDIF}
initialization
{$IFDEF CHARTGL_USE_LAZFREETYPE}
InitFonts;
{$ENDIF}
finalization
{$IFDEF CHARTGL_USE_LAZFREETYPE}
DoneFonts;
{$ENDIF}
end.