Bitmap Fonts - Speed up Trimming?
BlitzMax Forums/BlitzMax Programming/Bitmap Fonts - Speed up Trimming?| 
 | ||
| I'm writing a bitmap font library. It's fully-functional, but it needs a lot of optimization, specifically in the trimming of space off the sides of the character images. How is this typically done? Currently I'm going through every pixel and finding the right- and left-most solid pixels in each image, then drawing the image to the backbuffer, then grabbing the image using the coordinates I found earlier. It works perfectly, but it's incredibly slow--it takes about 2 seconds to trim a font. Any suggestions? | 
| 
 | ||
| If you are getting the font from a truetype and you are drawing the characters into images to create the bitmap font, which it kinda sounds like you are, then you can use the following blitzmax function to get the pixel width of the character. Just feed it one character at a time: Function TextWidth( text$ ) Returns the width, in pixels, of text based on the current image font. Description Get width of text Information This command is useful for calculating horizontal alignment of text when using the DrawText command. Its found in the Max2d module. | 
| 
 | ||
| Unfortunately I'm not--I'm using the bitmap fonts found here. Basically my problem was trimming off the empty space on the sides of each character efficiently--however I've found a different method and I've managed to cut the trimming time down to about 20 ms, and I've cut the loading time down to about 15 ms. Anyways here's the finished library if anybody wants it: '***********************************************************************************************************************************
'                                        B I T M A P   F O N T   L I B R A R Y
'***********************************************************************************************************************************
Rem
This library will allow you To draw bitmap fonts obtained from bitmap font image.
How To use it:
	-First, Load a font like so:
		
		Local Font:TBitmapFont = TBitmapFont.Load(FileName)
		
	where FileName is the filename of a bitmap font image.
	
	-Then draw text with the Draw() method:
	
		Font.Draw("Hello, world!", 100, 100)
		
	You can change the scale and rotation of the font as well, using SetScale() and SetAngle().
	
	You can also change the spacing of the font using SetSpacing(). You may need to set the spacing
	to a negative value in order to obtain the appearance you desire.
	
	You can also change the handle of the font with SetHandle(). The handle of the font is the center
	at which the font is rotated and scaled. Additionally you can center the font using SetCentered() and setting
	it to 1, which will automatically set the handle in the center of any text you draw.
		
EndRem
''***********************************************************************************************************************************
Type TBitmapFont
	Field Image:TImage
	
	Field Offset:Int[190]
	Field Spacing:Float
	
	Field CellWidth:Int
	Field CellHeight:Int
	
	Field HandleX:Float
	Field HandleY:Float
	Field Angle:Float
	Field ScaleX:Float
	Field ScaleY:Float
	Field Centered:Int
	
	Method GetWidth:Int(Text:String)
		Local CurIndex:Int
		Local CurWidth:Int
		
		For Local I:Int = 1 To Len(Text)
			CurIndex = Asc(Mid(Text, I, 1)) - 32
			CurWidth :+ (Offset[CurIndex * 2 + 1] - Offset[CurIndex * 2]) + Spacing
		Next
	
		Return CurWidth
	EndMethod
	Method GetHeight:Int()
		Return ImageHeight(Image)
	EndMethod
	
	Method SetSpacing(Space:Float)
		Spacing = Space
	EndMethod
	
	Method GetSpacing:Int()
		Return Spacing
	EndMethod
	
	Method SetHandle(X:Float, Y:Float)
		HandleX = X
		HandleY = Y
	EndMethod
	
	Method GetHandle(X:Float Var, Y:Float Var)
		X = HandleX
		Y = HandleY
	EndMethod
	
	Method SetCentered(IsCentered:Int)
		Centered = IsCentered
	EndMethod
		
	
	Method SetAngle(Ang:Float)
		Angle = Ang
	EndMethod
	
	Method GetAngle:Float()
		Return Angle
	EndMethod
	
	Method SetScale(X:Float, Y:Float)
		ScaleX = X
		ScaleY = Y
	EndMethod
	
	Method GetScale(X:Float Var, Y:Float Var)
		X = ScaleX
		Y = ScaleY
	EndMethod
	
	Method Draw(Text:String, X:Int, Y:Int)
		SetTransform(Angle, ScaleX, ScaleY)
	
		Local CurIndex:Int
		Local OrigX:Int = X
		
		Local OldHX:Float
		Local OldHY:Float
		
		If Centered
			OldHX = HandleX
			OldHY = HandleY
			HandleX = GetWidth(Text) / 2
			HandleY = GetHeight() / 2
		EndIf
		
		For Local I:Int = 1 To Len(Text)
			CurIndex = Asc(Mid(Text, I, 1)) - 32
			SetImageHandle(Image, -((X - Offset[CurIndex * 2]) - (OrigX + HandleX)),  HandleY)
			DrawImage(Image, OrigX, Y, CurIndex)
			X :+ Offset[CurIndex * 2 + 1] - Offset[CurIndex * 2]
			X :+ Spacing
		Next
		
		HandleX = OldHX
		HandleY = OldHY
		
	EndMethod
	
	Method Trim()
		Local Pixmap:TPixmap
	
		For Local I:Int = 0 To 94
		
			Pixmap = LockImage(Image, I)
                        Pixmap = Pixmap.Convert(PF_RGBA8888)
			
			Local LeftMax:Int = CellHeight - 1
			Local RightMax:Int = 0
			
			For Local Y:Int = 0 To CellHeight - 1
				For Local X:Int = 0 To CellWidth - 1
					Local Color:Int = Pixmap.ReadPixel(X, Y)
					If Color Shr 24 & $000000FF > 128
						If X < LeftMax
							LeftMax = X
						EndIf
						Exit
					EndIf
				Next
			Next
			
			For Local Y:Int = 0 To CellHeight - 1
				For Local X:Int = CellWidth - 1 To 0 Step -1
					Local Color:Int = Pixmap.ReadPixel(X, Y)
					If Color Shr 24 & $000000FF > 128
						If X > RightMax
							RightMax = X
						EndIf
						Exit
					EndIf
				Next
			Next
			
			If RightMax = 0
				RightMax = CellWidth - CellWidth / 3
			EndIf
			If LeftMax = CellWidth - 1
				LeftMax = CellWidth / 3
			EndIf
			
			LeftMax = LeftMax - Spacing / 2
			RightMax = RightMax + Spacing / 2
			
			If RightMax > CellWidth - 1
				RightMax = CellWidth - 1
			EndIf
			If LeftMax < 0
				LeftMax = 0
			EndIf
			
			Offset[I * 2] = LeftMax
			Offset[I * 2 + 1] = RightMax
			
			UnlockImage(Image, I)
		
		Next
	EndMethod
	Function Load:TBitmapFont(FileName:String)
		Local Font:TBitmapFont = New TBitmapFont
		
		Local FontImage:TImage = LoadImage(LoadBank(FileName))
		
		Local CellWidth:Int = ImageWidth(FontImage) / 10
		Local CellHeight:Int = ImageHeight(FontImage) / 10
		
		FontImage = LoadAnimImage(LoadBank(FileName), CellWidth, CellHeight, 0, 95)
		
		If Not FontImage
			Notify("The bitmap font image you specified does not exist, or is not of a supported file format.", True)
			End
		EndIf		
		Font.Image = FontImage
		Font.CellWidth = CellWidth
		Font.CellHeight = CellHeight
		Font.ScaleX = 1.0
		Font.ScaleY = 1.0
		
		Font.Trim()
		
		Return Font
	EndFunction
	
EndTypeHow To use it: -First, Load a font like so: Local Font:TBitmapFont = TBitmapFont.Load(FileName) where FileName is the filename of a bitmap font image. -Then draw text with the Draw() method: Font.Draw("Hello, world!", 100, 100)You can change the scale and rotation of the font as well, using Font.SetScale() and Font.SetAngle(). You can also change the spacing of the font using Font.SetSpacing(). You may need to set the spacing to a negative value in order to obtain the appearance you desire. You can also change the handle of the font with Font.SetHandle(). The handle of the font is the center at which the font is rotated and scaled. Additionally you can center the font using Font.SetCentered() and setting it to 1, which will automatically set the handle in the center of any text you draw. Here's a little example that demonstrates loading, centering, scaling, rotating, and drawing a font: SuperStrict
Include "TBitmapFont.bmx"
Graphics 1024, 768, 1
SetBlend(ALPHABLEND)
SetClsColor(0, 50, 200)
Local Font:TBitmapFont = TBitmapFont.Load("OrangeWithShadow.png")
Font.SetSpacing(-4)
Font.SetCentered(1)
Local Counter:Float
Local ScaleX:Float
Local ScaleY:Float
Local Ang:Float
Repeat
	Cls
	
	Font.SetAngle(0.0)
	Font.SetScale(1.0, 1.0)
	Font.Draw("Bitmap Font Library - Demo", GraphicsWidth() / 2, 20)
	
	Counter :+ 1.0
	
	ScaleX = Sin(Counter) * 3.0
	Font.SetScale(ScaleX, 3.0)
	Font.Draw("Hello, world!", MouseX(), MouseY())
	
	ScaleY = Sin(Counter) * 3.0
	Font.SetScale(3.0, ScaleY)
	Font.Draw("Hello, world!", MouseX(), MouseY() - 90)
	
	Ang = Sin(Counter) * 30.0
	Font.SetScale(2.0, 2.0)
	Font.SetAngle(Ang)
	Font.Draw("Hello, world!", MouseX(), MouseY() + 90)
	
	Flip
	
Until AppTerminate() Or KeyHit(KEY_ESCAPE)Note: You'll need the 'Orange' font found here to run the demo. | 
| 
 | ||
| Are those bitmap fonts free to use?  he mentions the games are free but i didn't see anything about the fonts | 
| 
 | ||
| Yes, as he says here and here. :) | 
| 
 | ||
| you know you are not using this correctly: Pixmap.Convert(PF_RGBA8888) that is not going to convert the original pixmap "automatically". | 
| 
 | ||
| Fontext can be used to make fonts for this code. | 
| 
 | ||
| ? | 
| 
 | ||
| Jesse - what is it that you don't understand? | 
| 
 | ||
| this: Fontext can be used to make fonts for this code. I didn't know where you were comming from. I got it now. I just realized that you were the creator of Fontext.:) http://www.blitzbasic.com/Community/posts.php?topic=65909 | 
| 
 | ||
| Jesse: Ahh, I see--is it just a matter of using the Pixmap returned by Convert() or is the their extra work involved? Beaker: Good to know. :) | 
| 
 | ||
| it needs to be like this pixmap = Pixmap.Convert(PF_RGBA8888) | 
| 
 | ||
| Thank you, I've edited it. |