Severe unwated Font Scalling on BlitzMax

BlitzMax Forums/BlitzMax Programming/Severe unwated Font Scalling on BlitzMax

yorchis2009(Posted 2013) [#1]
I am building a long horizontal text scroll. At first didit with drawtext directly to screen, worked alright at the cost of almost 70% my CPU!!!
So I decided to build my text on a Image object and scroll the masked image over, worked terrific and at less than 2% my CPU !!!

But suddenly I noticed strange behaveour with some strings, the longer the stranger!

- Longer string = Smaller or damaged font
- Smaller screen size = earlier chopped strings

Which is the right way to build a huge scrolling image on blitzmax?? I havent found any any copy function between pixmaps o Images, is this right ???


matibee(Posted 2013) [#2]
The done thing would be to use a bitmap font. The font would normally be a single texture, drawn to screen with a separate "drawsubimagerect" call for each character. It's worked well for everyone else around here.

This is one such module:
http://www.wieringsoftware.nl/blitz/

but it's been broken by later versions of blitzmax. My fix is here:
http://www.matibee.co.uk/wpsite/forum/general-2/bitmap-font-mod-revisited/


GfK(Posted 2013) [#3]
"Huge scrolling images", I would imagine, would have very odd dimensions. It's generally not recommended to have non^2 images, so that limits you to 32x32, 256x256 etc. It's not essential that they're square, but if they aren't, there may be issues on old hardware. None of this is a limitation of Blitzmax, but the PC hardware.

Your best solution is to only draw the text that's on the screen, rather than trying to draw the entire string every frame, even though 99% of it is off-screen. Even so, if something's taking up 70% CPU time, I'd suggest you're bypassing vSync either in your program, or at driver level. Try to put a Delay 1 into your main loop, or use Flip True.


GfK(Posted 2013) [#4]
The done thing would be to use a bitmap font.
I'm fairly sure that TTFs are internally converted to bitmap fonts at load-time anyway - even the built-in/default font is a bitmap font. Probably.


yorchis2009(Posted 2013) [#5]
Hi, Thank you very much guys here's my code if anyone would like to test... by the way I am developing in Linux so please change paths for windows fonts.

In this example my font is about 64 pixels height but whith this long string it goes down to 20 pixels height or so.

Mifont$ = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"
Local font:TImageFont=LoadImageFont(Mifont,42)

' Should work on any screen
txt$="Contrary to popular belief, Lorem Ipsum is not simply random text."
text$=txt$+txt$+txt$+txt$+txt$+txt$+txt$+txt$  ' This is to avoid filling up the post not the real code. But feel free to add more and more and see the font downgrade

' Creamos un image para guardar el letrero
Local uno:TGraphics=CreateGraphics( 100,100,0,60,GRAPHICS_BACKBUFFER)
SetGraphics (uno)
SetImageFont(font) 
Ancho = TextWidth(text) 
Alto = TextHeight(text)+15
CloseGraphics uno


Local Buffered:TGraphics=CreateGraphics(Ancho,Alto,0,60,GRAPHICS_BACKBUFFER )

SetGraphics (Buffered)
Cls

Print GraphicsWidth () + " : " + GraphicsHeight()
SetImageFont(font) 
SetBlend maskblend
SetColor 255,255,255  
DrawText text,0,0
Local Textimage=CreateImage(Ancho,Alto,1,DYNAMICIMAGE|MASKEDIMAGE)
GrabImage Textimage,0,1
 CloseGraphics Buffered

Const NTimer = 30
Const ScreenW=1280
Const Paso=3
Const EspaciosAntesDeSiguienteRepeticion = 3
Graphics ScreenW,768

CuadrosPorSegundo=CreateTimer(NTimer)
EspacioEntreReinicio = Int(TextWidth("W")*EspaciosAntesDeSiguienteRepeticion)
PrimerFinal = Ancho +  ScreenW + EspacioEntreReinicio
OtroFinal = ScreenW-EspacioEntreReinicio
SLx =0

For i=0 To PrimerFinal Step Paso
	WaitTimer(CuadrosPorSegundo)
	Cls
	SetBlend Alphablend
	DrawImage Textimage,ScreenW-i,10
	
	If PrimerFinal-i <OtroFinal Then
		' Si ya se acabo el letrero repetirlo adelante
		SLx=SLx+Paso
		DrawImage Textimage,ScreenW-SLx,10
		If SLX+Paso>OtroFinal Then  ' Si el segundo ya desplazo el primero vovler el primero a la posicion del segundo y dejar de dibujar el segundo			
			i=SLx
			SLx =0
		EndIf
	EndIf

	Flip
Next

WaitKey



yorchis2009(Posted 2013) [#6]
My question is why in the world is the font scaling itself? is there anyway to disable that? Is it settable?

or should I Print the text to another object kind, and which would that be?

P.D. I know I could get the scroll to work printing subsets of the string, but Why if Blitzmax is so good at graphics should this be need to be done like in the old days messing with the strings instead of bitmaps ?


GfK(Posted 2013) [#7]
You are creating a massively wide and not very tall image, which is what's causing the problem - it just doesn't fit within the standard constraints for images, and not by a long way. So, weirdness on varying levels is completely expected.

The methods used 'in the old days' are invariably more efficient, because they had to be. Really, that's the right way to do it.


matibee(Posted 2013) [#8]
I'm fairly sure that TTFs are internally converted to bitmap fonts at load-time anyway - even the built-in/default font is a bitmap font. Probably.


Yeah, that's correct. I've been doing so much other stuff with TTF's recently it lead me to talk out of my hat. Good job you're still here!


BlitzSupport(Posted 2013) [#9]
@matibee: Your bmfont fix doesn't seem to be accessible here -- gives a 403 permission error. I'm guessing you have to be logged in?


matibee(Posted 2013) [#10]
Oops. Fixed.


yorchis2009(Posted 2013) [#11]
Thank you GfK, I am glad to confirm the "way of the old days" remains the good way! =)
An matibee I havent had the chance to test your mod yet, but I positive it is also a solution to my problem.

I dont make too much of this blitz behaviour, but I think we may be looking at a small particular UBG. Since there is no way override this behaviour with settings, It is also dificult to predict, and it shows itself when your graphics size is bigger than your Monitor Screen!

That means thad drawtext, scales down your font when you print to a Graphics element bigger than the Monitor Resolution. It doesnt need to be "way bigger", making it much much bigger, just does it more noticeable.


*(Posted 2013) [#12]
Best way is to render each letter where it should be on screen, so for example rending "This is a game scroller" and rendering 'is a game' you would just render the letters for those words then let the program do something else.

A mistake loads of newcomers to programming do is render the entire scroller every frame when you only see a small section of the whole thing on screen. If you only render the section the people see they will not notice the difference BUT you can have a scroller of any length you want.


yorchis2009(Posted 2013) [#13]
thank you every one, thanks to your advice I can say I overcame (but NOT solved) the unwanted scaling issue. anyway I started without this problem, I was drawing text on each frame. The problem arised from "optimization" . BlitzMax still resizes for no known reason the fonts on my code (shown above)

I have double-checked, and I can confirm ANY kind of write a line or 50 lines, using weiring mod or not uses 99% percent of the CPU busy time. (remember I work in Linux so 99 %CPU means that whatever my computer is DOING 99% of this time is spent on my simple Scroller! in absolute values its around 15% my QuadCore )

15% May be acceptable, but my code above dropped my %CPU usage BELOW 1% !!!

So I should replay this results override that the best WAY is drawing text to the screen on each frame. Back on the middle age (AMOS- Amiga OS, there was no cpu time to draw text on each frame, we built "rasters" and viewports for many layer scrollers that way)

dont you think we should be looking for a way to drawtext directly to a TImage ?


yorchis2009(Posted 2013) [#14]
Now I have tested everything =)

Same behaviour (unwanted scaling and string Chop) with all of this:

1. "pixmaps" instead if Images
2 "wiering bitmap fonts" instead of plain DrawText
3 "Window" instead of "Graphics"
4 And "Canvas" to hold the huge landscape


MODIFIED CODE

Strict
Import MaxGui.Drivers
Import wiering.bmfont

Const SCREEN_W = 800
Const SCREEN_H = 600


' load font from incbin:: (be careful with upper/lowercase in the name!)
Incbin "/BlitzMax/samples/bitmapfont/Delicious_00.png"
Incbin "/BlitzMax/samples/bitmapfont/Delicious.fnt"
Local BMF: TBMFont = TBMFont.Create ("/BlitzMax/samples/bitmapfont/", "Delicious.fnt")

AppTitle = "OtraPrueba Max"

' Should work on any screen
Local txt$="Contrary to popular belief, Lorem Ipsum is not simply random text."
Local text$=txt$+txt$+txt$  +txt$+txt$+txt$+txt$+txt$ +txt$ +txt$ +txt$ ' This is to avoid filling up the post not the real code. But feel free to add more and more and see the font downgrade

' Creamos un image para guardar el letrero
Graphics 800,600

Cls
SetScale (0.5, 0.5)
BMF.DrawText ("Generating shadow textures...", 10, 10)
Flip ()

BMF.CreateShadow (2, $C0)  ' CreateShadow uses the backbuffer and should be used after Graphics

Local BMFTex: TBMFont = TBMFont.Create ( "/BlitzMax/samples/bitmapfont/", "tex.fnt")
BMFTex.ApplyTexture (LoadImage ("/BlitzMax/samples/bitmapfont/texture.png"))
BMFTex.CreateShadow (3, $80)

SetClsColor $30, $50, $70
SetBlend (ALPHABLEND)
  SetColor ($FF, $FF, $FF)
  SetScale (1.0, 1.0)
  BMFTex.ShadowX = 3
  BMFTex.ShadowY = 4
  BMFTex.Align = ALIGN_left


Local Ancho:Int =BMFTex. TextWidth(text) 
Local Alto:Int = BMFTex.TextHeight(text)+15
EndGraphics

Print Ancho + " , " + Alto
' OJOOOOOOOOOOO si es para ventana pitch de CreateGraphcis es 0 no la profundidad de color
'Local Buffered:TGraphics=CreateGraphics( Ancho,Alto,0,-1,-1 )
Local window:TGadget=CreateWindow("My Canvas",0,0,Ancho,Alto,Null,WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS)
Local BufferedCanvas:TGadget = CreateCanvas(0,0, Ancho,Alto,window)
Local Buffered:TGraphics=CanvasGraphics(BufferedCanvas)
DebugStop 
SetGraphics (Buffered)
Cls

'Print GraphicsWidth () + " : " + GraphicsHeight()

BMFTex.DrawText(text$,0,0)

Local Textimage:TPixmap =GrabPixmap (0,0,ancho,alto)
CloseGraphics Buffered

Const NTimer = 30
Const ScreenW=1280
Const Paso=3
Const EspaciosAntesDeSiguienteRepeticion = 3
Graphics ScreenW,768

Local CuadrosPorSegundo:TTimer =CreateTimer(NTimer)
Local EspacioEntreReinicio:Int = Int(TextWidth("W")*EspaciosAntesDeSiguienteRepeticion)
Local PrimerFinal:Int = Ancho +  ScreenW + EspacioEntreReinicio
Local OtroFinal:Int  = ScreenW-EspacioEntreReinicio
Local SLx:Int =0
Local i:Int =0

SetViewport 0,0,Ancho,alto
For i=0 To PrimerFinal Step Paso
	WaitTimer(CuadrosPorSegundo)
	Cls
	SetBlend Alphablend
'	SetHandle i,0
	DrawPixmap Textimage,ScreenW-i,10
'	DrawPixmap Textimage,ScreenW-i,10,Ancho,alto
	
	If PrimerFinal-i <OtroFinal Then
		' Si ya se acabo el letrero repetirlo adelante
		SLx=SLx+Paso
	'	DrawImage Textimage,ScreenW-SLx,10
	'	SetHandle SLx,0
		DrawPixmap  Textimage,ScreenW-SLx,10
		If SLX+Paso>OtroFinal Then  ' Si el segundo ya desplazo el primero vovler el primero a la posicion del segundo y dejar de dibujar el segundo			
			i=SLx
			SLx =0
		EndIf
	EndIf

	Flip
Next

WaitKey



matibee(Posted 2013) [#15]
Just use "Flip 1" to force vsync and your app will sit idle for most of the time consuming no cpu at all.

Some random numbers:

With vsync off, no drawing code you get 2,000 frames per second or 0.0005 seconds per frame. 2,000 fps wow amazing!

Then you add drawing code that takes 0.001 (1/1000th) of a second. Ooops your fps just dropped to 666. Did that little bit of code take up 2/3rds of my app time? No, not really.

Both cases above are stressing your CPU (or one core at least) 100% and possibly result in vertical tearing or shearing when the screen flips are not timed with the refresh rate of your monitor (which is pretty much all the time - you just don't see it that often).

Now switch to using vsync.

The loop of our app above runs in 0.0015 seconds but your monitor refresh rate is 100hz (0.01 seconds). So the app must sit around waiting for 0.0085 seconds before it needs to do anything else.

So instead of having 1 core running flat out to provide an inferior and pointless 666fps display, we have it running at just 1/6th capacity providing s silky smooth 100fps.

This is very, very old ground you're going over. Have a search around the forums.


yorchis2009(Posted 2013) [#16]
Hi, I am sorry matibee, now I am totally lost ! =)
I dont see any vsync command or function on BlitzMax what do you mean with vsync? to "manually" sync monitor Vertical Reresh Time with the flip times?

I have search the forum and I cant find enaough vsync explanations besides de Blitz3D ones.

do you have a piece of code for a vsync BlitzMax example?


*(Posted 2013) [#17]
Flip 1 will make it sync to the hertz set at the end of the graphics command