{* UltraStar Deluxe - Karaoke Game * * UltraStar Deluxe is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * $URL$ * $Id$ *} unit TextGL; interface {$IFDEF FPC} {$MODE Delphi} {$ENDIF} {$I switches.inc} uses gl, glext, SDL, Classes, UTexture, UFont, UPath, ULog; type PGLFont = ^TGLFont; TGLFont = record Font: TScalableFont; Outlined: boolean; X, Y, Z: real; end; const ftNormal = 0; ftBold = 1; ftOutline1 = 2; ftOutline2 = 3; var Fonts: array of TGLFont; ActFont: integer; procedure BuildFonts; // builds all fonts procedure KillFonts; // deletes all font function glTextWidth(const text: UTF8String): real; // returns text width procedure glPrint(const text: UTF8String); // custom GL "Print" routine procedure ResetFont(); // reset font settings of active font procedure SetFontPos(X, Y: real); // sets X and Y procedure SetFontZ(Z: real); // sets Z procedure SetFontSize(Size: real); procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc) procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts) procedure SetFontReflection(Enable:boolean;Spacing: real); // enables/disables text reflection implementation uses UTextEncoding, SysUtils, IniFiles, UCommon, UMain, UPathUtils; {** * Returns either Filename if it is absolute or a path relative to FontPath. *} function FindFontFile(const Filename: string): IPath; begin Result := FontPath.Append(Filename); // if path does not exist, try as an absolute path if (not Result.IsFile) then Result := Path(Filename); end; procedure AddFontFallbacks(FontIni: TMemIniFile; Font: TFont); var FallbackFont: IPath; IdentName: string; I: Integer; begin // evaluate the ini-file's 'Fallbacks' section for I := 1 to 10 do begin IdentName := 'File' + IntToStr(I); FallbackFont := FindFontFile(FontIni.ReadString('Fallbacks', IdentName, '')); if (FallbackFont.Equals(PATH_NONE)) then Continue; try Font.AddFallback(FallbackFont); except on E: EFontError do Log.LogError('Setting font fallback ''' + FallbackFont.ToNative() + ''' failed: ' + E.Message); end; end; end; const FONT_NAMES: array [0..3] of string = ( 'Normal', 'Bold', 'Outline1', 'Outline2' ); procedure BuildFonts; var I: integer; FontIni: TMemIniFile; FontFile: IPath; Outline: single; Embolden: single; OutlineFont: TFTScalableOutlineFont; SectionName: string; begin ActFont := 0; SetLength(Fonts, Length(FONT_NAMES)); FontIni := TMemIniFile.Create(FontPath.Append('fonts.ini').ToNative); try for I := 0 to High(FONT_NAMES) do begin SectionName := 'Font_'+FONT_NAMES[I]; FontFile := FindFontFile(FontIni.ReadString(SectionName , 'File', '')); // create either outlined or normal font Outline := FontIni.ReadFloat(SectionName, 'Outline', 0.0); if (Outline > 0.0) then begin // outlined font OutlineFont := TFTScalableOutlineFont.Create(FontFile, 64, Outline); OutlineFont.SetOutlineColor( FontIni.ReadFloat(SectionName, 'OutlineColorR', 0.0), FontIni.ReadFloat(SectionName, 'OutlineColorG', 0.0), FontIni.ReadFloat(SectionName, 'OutlineColorB', 0.0), FontIni.ReadFloat(SectionName, 'OutlineColorA', -1.0) ); Fonts[I].Font := OutlineFont; Fonts[I].Outlined := true; end else begin // normal font Embolden := FontIni.ReadFloat(SectionName, 'Embolden', 0.0); Fonts[I].Font := TFTScalableFont.Create(FontFile, 64, Embolden); Fonts[I].Outlined := false; end; Fonts[I].Font.GlyphSpacing := FontIni.ReadFloat(SectionName, 'GlyphSpacing', 0.0); Fonts[I].Font.Stretch := FontIni.ReadFloat(SectionName, 'Stretch', 1.0); AddFontFallbacks(FontIni, Fonts[I].Font); end; except on E: EFontError do Log.LogCritical(E.Message, 'BuildFont'); end; // close ini-file FontIni.Free; end; // Deletes the font procedure KillFonts; var I: integer; begin for I := 0 to High(Fonts) do Fonts[I].Font.Free; end; function glTextWidth(const text: UTF8String): real; var Bounds: TBoundsDbl; begin Bounds := Fonts[ActFont].Font.BBox(Text, true); Result := Bounds.Right - Bounds.Left; end; // Custom GL "Print" Routine procedure glPrint(const Text: UTF8String); var GLFont: PGLFont; begin // if there is no text do nothing if (Text = '') then Exit; GLFont := @Fonts[ActFont]; glPushMatrix(); // set font position glTranslatef(GLFont.X, GLFont.Y + GLFont.Font.Ascender, GLFont.Z); // draw string GLFont.Font.Print(Text); glPopMatrix(); end; procedure ResetFont(); begin SetFontPos(0, 0); SetFontZ(0); SetFontItalic(False); SetFontReflection(False, 0); end; procedure SetFontPos(X, Y: real); begin Fonts[ActFont].X := X; Fonts[ActFont].Y := Y; end; procedure SetFontZ(Z: real); begin Fonts[ActFont].Z := Z; end; procedure SetFontSize(Size: real); begin Fonts[ActFont].Font.Height := Size; end; procedure SetFontStyle(Style: integer); begin ActFont := Style; end; procedure SetFontItalic(Enable: boolean); begin if (Enable) then Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Italic] else Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Italic] end; procedure SetFontReflection(Enable: boolean; Spacing: real); begin if (Enable) then Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style + [Reflect] else Fonts[ActFont].Font.Style := Fonts[ActFont].Font.Style - [Reflect]; Fonts[ActFont].Font.ReflectionSpacing := Spacing - Fonts[ActFont].Font.Descender; end; end.