unit guitextobject; //renders a font. //right now it just renders a single texture with the required text and updates it as needed //todo: build a fontmap {$mode objfpc}{$H+} interface uses Classes, SysUtils, graphics, guiobject, gamepanel, gl,glext,math, controls; type TTextAlign=(taLeft, taCenter, taRight); TGUITextObject=class(TGuiObject) private ftext: string; //just as an indication if the texture needs to be updated fbackgroundcolor: tcolor; //for anti alliasing fforegroundcolor: tcolor; ftexture: integer; ffont: tfont; fwidth, fheight: single; fLineSpacing: integer; fbackgroundAlpha: byte; fKeepAspectRatio: boolean; procedure setFont(f: tfont); protected function getTexture: integer; override; function getWidth:single; override; procedure setWidth(w: single); override; function getHeight:single; override; procedure setHeight(h:single); override; public minWidth: integer; //minimal pixel width for the texture minheight: integer; firstTextBecomesMinWidth: boolean; textAlignment: TTextAlign; procedure setText(text: string); constructor create(owner: TGamePanel=nil); destructor destroy; override; property Text: string read ftext write setText; property font: tfont read ffont write setFont; property linespacing: integer read flinespacing write flinespacing; property color: tcolor read fforegroundcolor write fforegroundcolor; property bcolor: tcolor read fbackgroundcolor write fbackgroundcolor; property backgroundAlpha: byte read fbackgroundAlpha write fbackgroundAlpha default 0; property keepAspectRatio: boolean read fKeepAspectRatio write fkeepAspectRatio; end; implementation function TGUITextObject.getTexture: integer; begin result:=ftexture; end; function TGUITextObject.getWidth:single; begin result:=fwidth; end; procedure TGUITextObject.setWidth(w: single); begin fwidth:=w; end; function TGUITextObject.getHeight:single; begin result:=fheight; end; procedure TGUITextObject.setHeight(h: single); begin fheight:=h; end; procedure TGUITextObject.setText(text: string); var img: TBitmap; pp: pointer; p: pdword; th, tw,iw,ih: integer; i: integer; backgroundcolorbgr: dword; sl: tstringlist; ba: dword; ar: single; begin if ftext<>text then begin sl:=TStringList.create; sl.text:=text; //update the texture img:=TBitmap.Create; img.PixelFormat:=pf32bit; img.canvas.font:=font; tw:=img.Canvas.TextWidth(text); tw:=0; th:=0; for i:=0 to sl.Count-1 do begin if i>0 then inc(th, fLineSpacing); inc(th,img.Canvas.TextHeight(sl[i])); tw:=max(img.Canvas.TextWidth(sl[i]), tw); end; if (minwidth=0) and firstTextBecomesMinWidth then minwidth:=tw; if (minheight=0) and firstTextBecomesMinWidth then minheight:=th; if fKeepAspectRatio then begin tw:=max(minWidth,tw); th:=max(minHeight,th); //increase tw and th to the aspect ratio given ar:=height/width; i:=trunc(tw*ar); th:=max(i,th); ar:=width/height; i:=trunc(th*ar); tw:=max(i,tw); img.width:=max(minWidth,tw); img.Height:=max(minHeight,th); end else begin img.width:=max(minWidth,tw); img.Height:=max(minHeight,th); end; img.canvas.font.Color:=fforegroundcolor; img.canvas.Brush.Color:=fbackgroundcolor; //will be made transparant img.Canvas.FillRect(0,0,img.width, img.height); backgroundcolorbgr:=ColorToRGB(fbackgroundcolor); backgroundcolorbgr:=((backgroundcolorbgr shr 16) and $ff)+((backgroundcolorbgr shl 16) and $ff0000)+(backgroundcolorbgr and $ff00); // backgroundcolorbgr:=Swap(backgroundcolorbgr); th:=0; for i:=0 to sl.count-1 do begin tw:=img.Canvas.TextWidth(sl[i]); case textAlignment of taLeft: img.Canvas.TextOut(0,th,sl[i]); taCenter: img.Canvas.TextOut((img.width div 2)-(tw div 2),th,sl[i]); taRight: img.Canvas.TextOut(img.width-tw,th,sl[i]); end; inc(th,img.Canvas.TextHeight(sl[i])+fLineSpacing); end; iw:=img.width; ih:=img.height; glBindTexture(GL_TEXTURE_2D, ftexture); glActiveTexture(GL_TEXTURE0); pp:=img.RawImage.Data; //FPC sets the alpha channel to 100% transparant by default p:=pp; i:=0; ba:=backgroundAlpha shl 24; while i