Code archives/Graphics/TFont Antialias 2D font system for realtime
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| I have write this small library in order to obtain very beauty fonts even with small characters. The Library can works prefectly for realtime and the results are impressive, from my point of view. The functions could be very useful for games that needs to give a special attention to the text, like sports managers or something similar, even every scoreboard, popup windows in your games... I hope you find this useful and someone improve this easy library!! | |||||
;
; ************************************************************
; * Project Name: TFont2D - Antialiased 2D text v1.0 for realtime
; * Author(s): Pinete
; * Date Started: -
; * Last Updated: -
; * Website: -
; * Email:
; * Version: 1.0
; * Copyright: Donated to the public domain
; * Trademark: -
; * Product: -
; ************************************************************
;
;
; Based on the piece of code called "Anti-Alias Simulation"
; by Daniel Nobis who gives thanks to Triton für die Idee.
;
; I think I have improved the code to obtain a useful library for scoreboards,
; sports management games or, in general, games that need to use very small fonts or
; the text is important.
;
; I have tried to comment all the code.
; The library and all its functions are really easy to use and modify.
; The code is not brilliant, of course, and I'm sure that everybody with
; a little more knowledge than me can improve the functions a lot.
; At least I have achieve my first goal, doing my first contribution to the community.
;
; How it works?
;
; First a blank image is created, with the size of the character we will draw within.
; After that, we draw a rectangle with the color we want to antialiased with.
; Scale the image by half.
; Now, we mask the image with the background color.
; The result is the character with the antialiased pixels but whitout the background.
; That's the action that we will do with all the characters beetween 31 and 128
; And we will do again with differents background colors (from black to white)
; in order to obtain fonts with antialias for different backgrounds (five by default)
; We will do the same with the shadow.
; The last point is to draw the text.
; To do that, it reads the pixel of the graphic buffer (backbuffer, for example, and after draw the background)
; with the goal of obtain the most similar generated antialias to draw the character on to that background.
;
; From my point of view its usage is very comfortable and easy to manage and modify for a personal adaptation.
; It's very far to be fantastic but it is a way to print beauty strings at screen whitout use the 3Ds and
; with a very nice result.
;
; :)
;
; Should be fantastic if somebody could improve it in terms of speed or flexibility.
; Thanks to all that support blitbasic and blitzcoder community.
;
; The code has been writed using BB3D v1.87 and Protean Editor
; using four or five hours more or less.
;
; I hope you find this useful!
;
; List of functions
; -------------------
;
; TFontCreate
; TFontDraw
; TFontSet
; TfontGetWidth
; TFontShadow
; TFontShadowDistance
; TFontSetAutoGrad
; TFontSetGrad
; TFontDebugON
; TFontDebugOFF
;
Type TipoFont
Field Tchar[255]
Field Tlongx[255]
Field Tlongy[255]
Field TShadow[255]
Field ent
Field ref
End Type
Type TipoShadow
Field Tchar[255]
Field Tlongx[255]
Field Tlongy[255]
Field TShadow[255]
Field ent
Field ref
End Type
; Internal variables
Const GradSteps = 5 ; Number of steps in which the antialias is precalculated (from black to white)
Const MaxFonts = 255 ; Maximum fonts to be host
Dim fnt.TipoFont(GradSteps,MaxFonts) ; Host the fonts
Dim shw.TipoFont(GradSteps,MaxFonts) ; Host its shadows
Global TBoolShadow = -1 ; Shadow Bool. -1 = OFF, 1 = ON
Global TShadowDistX = 1
Global TShadowDistY = 1
Global TFontDefaultGrad = 3 ; Sets the default grad if it is not automatic
Global TFontFont = 1 ; Current Font
Global TFontBoolDEBUG = -1 ; Debug for each string
; it will show the current grad level, x,y, 2D width and 2D Height
; Framerate variables
Const FPS=85
Const debug=0
Global FPS_Oldtime, FPS_Newtime, FPS_Ticks
Global FPS_Current,FPS_Final
Global FPS_SampleRate = 5 ;Take a sample every N ticks
Global FPS_Samples = 10 ;Samples to average (res of the average)
Global FPS_BufferIndex = 1
Global FPS_Font
Dim FPS_Buffer(10)
Function TFontCreate.TipoFont(ref = 1,font,r1=255,g1=255,b1=255)
; You need to call this function before your main loop starts.
; To create a font, depending of the computer specs will need
; 1 second (aprox). Surely you will need various fonts in your
; game, and using 1 second per font, the creation of five fonts
; would take about 5 or 6 seconds, more or less.
;
;
;
;ref - Is the "reference" of the fonts. It is a number that will identify the font.
; Each font need a different reference when it is going to be created
;
;font - The font handle returned by the BB function "Loadfont"
;
;r1,g1,b1 - The RGB color of the font. The fonts cannot change its color in realtime because
; is a very slow process. In order to have various colours for the fonts, they need to
; be generated previously.
; Init RGB and misc vars for the background antialias
Local CharBegin = 31
Local CharFinal = 122
r = 0
g = 0
b = 0
grad = 1
; Select the font
SetFont font
; Generate the fonts with the antialias for the diferent gradients
For gr = 1 To GradSteps
fnt(gr,ref) = New TipoFont
For c = CharBegin To CharFinal
char$ = Chr$(c)
fnt(grad,ref)\Tchar[c] = CreateImage(StringWidth(char$),StringHeight(char$))
fnt(grad,ref)\Tlongx[c] = StringWidth(char$)/2
fnt(grad,ref)\Tlongy[c] = StringHeight(char$)
SetBuffer ImageBuffer(fnt(grad,ref)\Tchar[c])
Color r,g,b
Rect 0,0,ImageWidth(fnt(grad,ref)\Tchar[c]),ImageHeight(fnt(grad,ref)\Tchar[c])
Color r1,g1,b1
Text 0,0,char$
MaskImage fnt(grad,ref)\Tchar[c],r,g,b
ScaleImage fnt(grad,ref)\Tchar[c],0.5,0.5
Next
;DebugLog ("-> Antialias created for RGB: "+Str$(r)+","+Str$(g)+","+Str$(b))
r = r + Int(255/(GradSteps-1));63
g = g + Int(255/(GradSteps-1))
b = b + Int(255/(GradSteps-1))
grad = grad + 1
Next
; Generate the Shadows for each font, again, with the same number of antialias levels
; init RGB for the background antialias
r = 0
g = 0
b = 0
grad = 1
SetFont font
; Generate the antialias for the diferent gradients
For gr = 1 To GradSteps
shw(gr,ref) = New TipoFont
For c = CharBegin To CharFinal
char$ = Chr$(c)
shw(grad,ref)\Tchar[c] = CreateImage(StringWidth(char$),StringHeight(char$))
shw(grad,ref)\Tlongx[c] = StringWidth(char$)/2
shw(grad,ref)\Tlongy[c] = StringHeight(char$)
SetBuffer ImageBuffer(shw(grad,ref)\Tchar[c])
Color r,g,b
Rect 0,0,ImageWidth(shw(grad,ref)\Tchar[c]),ImageHeight(shw(grad,ref)\Tchar[c])
Color 50,50,50 ;The shadow color can be altered. 50,50,50 is not a pure black.
Text 0,0,char$
MaskImage shw(grad,ref)\Tchar[c],r,g,b
ScaleImage shw(grad,ref)\Tchar[c],0.5,0.5
Next
;DebugLog ("-> Shadow Antialias created for RGB: "+Str$(r)+","+Str$(g)+","+Str$(b))
r = r + Int(255/(GradSteps-1))
g = g + Int(255/(GradSteps-1))
b = b + Int(255/(GradSteps-1))
grad = grad + 1
Next
SetBuffer BackBuffer()
End Function
Function TFontDraw(cad$,x,y)
;
; It works like the standard BB function.
; Just to pass the string (cad$) and its 2D coordinates.
; Of course, it's a need to create the font with TcreateFont(...) previous to this call
;
;
; GradType = 0 for automatic selection of Antialias Gradient
; GradType = 1 to 5 for manual selection
; 1...Darkest (black background)
; 5...White
Local cx,cy
Local ref
cx = x
cy = y
Local numchar
Local GradTypeMode
GradTypeMode = TFontDefaultGrad
ref = TFontFont
; Let's see if we are debugging strings...
If TFontBoolDEBUG > 0
cad$ = cad$ + " -> "+Str$(TFontDefaultGrad)+", "+Str$(x)+", "+Str$(y)+", "+Str$(TfontGetWidth(cad$))
EndIf
If GradTypeMode <> 0 Then GradType = GradTypeMode
For r = 1 To Len(cad$)
numchar = Asc(Mid(cad$,r,1))
If GradTypeMode = 0 Then GradType = TExtractColorSingle(cx+1,cy+1)
If TBoolShadow > 0 Then DrawImage shw(GradType,ref)\Tchar[numchar],cx+TShadowDistX,cy+TShadowDistY
DrawImage fnt(GradType,ref)\Tchar[numchar],cx,cy
cx = cx + fnt(GradType,ref)\Tlongx[numchar]
Next
End Function
Function TFontSet(nFont)
; Sets the current font to use.
TFontFont = nFont
End Function
Function TfontGetWidth(wcad$)
; Return the 2D width in pixels of the string with the current font and with
; This could be useful to detect clicks and something similar...
Local ms
Local numch
Local ref
ms = 0
ref = TFontFont
For r = 1 To Len(wcad$)
numch = Asc(Mid(wcad$,r,1))
ms = ms + fnt(1,ref)\Tlongx[numch]
Next
Return ms
End Function
Function TFontShadow(bs)
; Activate or Deactivate Shadow for the current font.
; Using a parameter lower or equal to 0 the shadows will be OFF
; Using a parameter higher than 0 the shadows will be ON
;
; Remember, using shadows is a bit slower than drawing the normal text
; because you are drawing two strings!
; However, if you are not managing a really great quantity of text at screen,
; you could use shadows whitout any problem.
If bs > 0 Or bs = True Then TBoolShadow = 1
If bs <= 0 Or bs = False Then TBoolShadow = -1
End Function
Function TFontShadowDistance(xd,yd)
; Just define the distance of the shadows
; xd is the x distance in pixels
; yd is the y distance in pixels
; normal values are 1,1 or 2,2 for both parameters.
TShadowDistX = xd
TShadowDistY = yd
End Function
Function TExtractColorSingle(xe,ye)
; FOR INTERNAL USE ONLY
; Basically this function makes a very simple task.
; Just read the pixel at the coordinates in which the character will be printed
; in order to obtain its color information.
; After that, it look for the best gradient of the generated text in order to
; select the better visual result.
LockBuffer
; Check for the first point
TRead1 = ReadPixelFast(xe,ye,BackBuffer())
red# =((TRead1 Shr 16) And $FF)
green#=((TRead1 Shr 8)And $FF)
blue# =((TRead1 And $FF))
res1 = red + green + blue
Pass = Int(255/(GradSteps-1))
;Rgrad1 = (res1+63)/3/63
Rgrad1 = (res1+Pass)/3/Pass
UnlockBuffer
RetGrad = Int(Rgrad1)+1
If RetGrad>GradSteps Then RetGrad = GradSteps
Return RetGrad
End Function
Function TExtractColorMultiple(xe,ye)
; FOR INTERNAL USE ONLY
; This function is identical to the previous one, just with the difference
; that this time, it read two pixel and extract the media.
LockBuffer
; Check for the first point
TRead1 = ReadPixelFast(xe+2,ye+2,BackBuffer())
red# =((TRead1 Shr 16) And $FF)
green#=((TRead1 Shr 8)And $FF)
blue# =((TRead1 And $FF))
res1 = red + green + blue
Rgrad1 = (res1+Int(255/(GradSteps-1)))/3/(Int(255/(GradSteps-1)))
; Check for the second one
TRead2 = ReadPixelFast(xe+6,ye+6,BackBuffer())
red# =((TRead2 Shr 16) And $FF)
green#=((TRead2 Shr 8)And $FF)
blue# =((TRead2 And $FF))
res2 = red + green + blue
Rgrad2 = (res2+Int(255/(GradSteps-1)))/3/(Int(255/(GradSteps-1)))
; Make the media
Rgrad = (Rgrad1 + Rgrad2) / 2
UnlockBuffer
RetGrad = Int(Rgrad)+1
If RetGrad>GradSteps Then RetGrad = GradSteps
Return RetGrad;Int(Rgrad)+1
End Function
Function TFontSetGrad(defgrad = 0)
; Sets manually the gradient to use with the current font.
; Default gradients works in the range from 1 to 5.
; If the selected gradient is 0 the selection turn automatic for each character looking for
; the best result-
; Default is automatic (=0)
If defgrad > GradSteps Then defgrad = GradSteps
If defgrad < 0 Then deafgrad = 0
TFontDefaultGrad = defgrad
;DebugLog(TFontDefaultGrad)
Return defgrad
End Function
Function TFontSetAutoGrad()
; No parameters. Just call this function to set the automatic selection
; of gradient for each character.
TFontDefaultGrad = 0
End Function
Function TFontDebugON()
; Activate the debug mode for strings.
; Its a silly function that show, after draw each string, an addon that
; contains info about its gradient, x and y coordinates and 2D width.
TFontBoolDEBUG = -1
End Function
Function TFontDebugOFF()
; Deactivate the debug mode for strings.
TFontBoolDEBUG = 1
End Function
Function Get_FPS(PosX#=10,PosY#=2)
; This function is not of my property.
; It's a very useful function to scan the media of FPS.
; I dont remember who is the original autor.
; The credits goes for him as well, of course.
; I'm sorry for this.
FPS_Newtime = MilliSecs()
FPS_Ticks = FPS_Ticks + 1
If FPS_Ticks > FPS_SampleRate Then
FPS_Current = FPS_Newtime - FPS_Oldtime
If FPS_Current = 0 Then FPS_Current = 1000 Else FPS_Current = 1000/FPS_Current
FPS_Buffer(FPS_BufferIndex) = FPS_Current
FPS_BufferIndex = FPS_BufferIndex + 1
If FPS_BufferIndex > FPS_Samples Then
For FPS_Count = 1 To FPS_Samples
FPS_Master = FPS_Master + FPS_Buffer(FPS_Count)
Next
FPS_Final = FPS_Master / FPS_Samples
FPS_BufferIndex = 1
EndIf
FPS_Ticks = 0
EndIf
FPS_Oldtime = MilliSecs()
Text(PosX#,PosY#,"iFPS:"+FPS_Final)
End Function |
Comments
| ||
| Excellent stuff, a wee hidden gem! :) |
Code Archives Forum