Is there a bug with drawing text to images in B+?

BlitzPlus Forums/BlitzPlus Programming/Is there a bug with drawing text to images in B+?

sswift(Posted 2005) [#1]
; -----------------------------------------------------------------------------------------------------------------------------------
; This function draws rotated text at the specified location on the screen. 
; It works exactly like the text command.  
; The text is drawn in the current drawing color.
;
; The only limitation is that black text will not work with this function. 
; If you need black text, use Color 1,1,1 instead.
;
; This function disables TFormFilter.  You will need to renenable TformFilter after calling this function if you need it enabled.
; -----------------------------------------------------------------------------------------------------------------------------------
Function RotatedText(StringToOutput$, X, Y, Center_X=False, Center_Y=False, Angle)

	Local OldBuffer
	Local TempImage
	
	; Store the currently active drawing buffer.
		OldBuffer = GraphicsBuffer()

	; Create an image to hold the text we want to rotate.					
		TempImage = CreateImage(128, 128) ; StringWidth(StringToOutput$), StringHeight(StringToOutput$))
	
	; Set the drawing buffer to that of the image we want to put the text on.			
		SetBuffer ImageBuffer(TempImage)
	
	; Draw the text to the temporary image.
		Text 0, 0, Ev$
	
	; Rotate the image.  This changes the size of the image.			
;		TFormFilter False
;		RotateImage TempImage, Angle
		
	; Fix the image mask.
;		MaskImage TempImage, 0, 0, 0
		
	; Draw the rotated image at the specified location on the screen.	
		
		SetBuffer OldBuffer
		
;		If Center_X Then X = X - ImageWidth(TempImage)/2
;		If Center_Y Then Y = Y - ImageHeight(TempImage)/2
		
		DrawImage TempImage, X, Y
		
	; Clean up.
		FreeImage TempImage

End Function



Does anyone see a bug in the above code?

I set my drawing buffer to an image, I draw two lines of regular white text to confirm that I have set the buffer properly, and then I call this function.

The two lines of regular text appear as expected, but no additional text appears on the screen.

As you can see I've been commenting bits of the function out here and there to try to find the problem, but so far no dice.

Actually now that I think of it... I am writing that OTHER text to an image. It's just that the text I'm wriitng in this function is either not going into the image, or the image it is being drawn to is not being output.


sswift(Posted 2005) [#2]
Ugh, nevermind, I am an idiot I see the problem now. I copied and pasted some of the code from another section of the code and forgot to change Ev$ to the variable the function passes the text in.


sswift(Posted 2005) [#3]
Sigh...

Another "bug" to report.

My nice encapsulated function that works the same as the text function works great if you want to use the default arial font, but I just noticed that the blitzplus requires you to set the font for every buffer you're accessing.

There is no command to get the font currently in use however. This means that while:

SetFont(Blah)
Text 10,10, "Blah"

Works just fine, there is no way for me to implement my function so that:

SetFont(Blah)
RotatedText 10,10, "Blah"

Also works. Because my function needs to write text to a completey different buffer than the currently active one before blitting it.


Oh, and the image rotation functions still suck. I just ran into the same issue I had with my scorched earth game. If I rotate my text by 90 degrees, it's off by a pixel or two, because Blitz cannot rotate images which have an even size properly. It is for some godforsaken reason written to work correctly only with odd sized images.

Ie, make a two pixel wide vertical line. Rotate it by 90 degrees. Line is now horizontal, but shifted down by one pixel so it is no longer centered in the image as you would expect it to be.

Rotating 90 degrees counterclockwise has opposite effect.

It works great for odd sized images. BUT WHO USES ODD SIZED IMAGES?

So my rotated text ends up being off by a pixel in one direction of another.

On top of the fact that I now have to require the user to pass the font they want the text drawn in to the function every time they want to draw text.


sswift(Posted 2005) [#4]
Oh and did I mention the docs for the requestfont() command don't exist?


sswift(Posted 2005) [#5]
Ugh, I give up on this rotated text function, I wasted too much time on it, and because of how Blitz rotates images and offsets the image handle when the image is rotated, it makes it impossible to position the text precisely. I'm sure I could fix it with a bunch of kludges, but just forget it. Not worth the time and effort just to have text printed vertically.

; -----------------------------------------------------------------------------------------------------------------------------------
; This function draws rotated text at the specified location on the screen.  It works exactly like the text command.  
; The text is drawn in the current drawing color.
;
; Because the function uses masked images to draw the text, black text will not work with this function. 
; If you need black text, use Color 1,1,1 instead.

; Parameters:
; Angle is the angle to draw the text at.  0 = Unrotated, 90 = 90 degrees clockwise rotation.
; If you set masked to FALSE, them the text will be drawn with a solid black baground behind it.
; Border allows you to make the black background a few pixels larger than the text when drawing text which is not masked.
;
; Keep in mind that when you rotate the text, the location you specify will be the top left corner of the first letter.
; If you rotate the text by 90 degrees, and then print it at (0,0) the text will be drawn off the screen.
;
; This function disables TFormFilter.  You will need to renenable TformFilter after calling this function if you need it enabled.
; -----------------------------------------------------------------------------------------------------------------------------------
Function RotatedText(Font, StringToOutput$, X, Y, Center_X=False, Center_Y=False, Angle, Masked=True, Border=0)

	Local OldBuffer
	Local TempImage
		
	; Store the currently active drawing buffer.
		OldBuffer = GraphicsBuffer()

	; Set the font to draw the text in so that we can find out how big an image we need for our string.
		SetFont Font 

	; Create an image to hold the text we want to rotate.					
		TempImage = CreateImage(StringWidth(StringToOutput$), StringHeight(StringToOutput$))
	
	; Set the drawing buffer to that of the image we want to put the text on.			
		SetBuffer ImageBuffer(TempImage)

	; Set the font to draw the text in AGAIN, because we have to set the font for each buffer we want to draw to.
		SetFont Font 
	
	; Draw the text to the temporary image.
		Text 0, 0, StringToOutput$
	
	; Rotate the image.  This changes the size of the image.			
		TFormFilter False
		RotateImage TempImage, Angle
	
	; Draw the rotated image at the specified location on the screen.	
		
		SetBuffer OldBuffer
		
		If Center_X Then X = X - ImageWidth(TempImage)/2
		If Center_Y Then Y = Y - ImageHeight(TempImage)/2

		If Masked 		
			DrawImage TempImage, X, Y
		Else
			DrawBlock TempImage, X, Y
		EndIf
		
	; Clean up.
		FreeImage TempImage

End Function



Grey Alien(Posted 2005) [#6]
How about making ssSetFont which takes your font parameters, stores them globally in your RotatedText unit and then sets the font for the current buffer. Then your RotatedText function can retrieve them when it needs to set the same font up for its buffer. You probably already thought of this though?

btw, do you know if DrawBlock is any faster than draw image for non-masked images?

I know you were trying to make a reusable function, but you could easily write a mini function to rotate by 90 degrees only and not use RotateImage function.


sswift(Posted 2005) [#7]
Aaand... now there's no way to get the width and height of the current graphics buffer, so I can't make a generalized function for drawing a multiply blended rectangle to the current buffer.

; -----------------------------------------------------------------------------------------------------------------------------------
; This function draws a rectangle of the specified color using multiply blending to the current buffer.
; -----------------------------------------------------------------------------------------------------------------------------------
Function Draw_Rect(X1, Y1, X2, Y2, ColorR, ColorG, ColorB)

	Local LoopX, LoopY

	DestBuffer = GraphicsBuffer()
	
 
			
	LockBuffer(DestBuffer)
	For LoopY = Y1 To Y2
		For LoopX = X1 To X2

			RGB = ReadPixelFast(LoopX, LoopY, DestBuffer) 
		
			R = (RGB Shr 16) And 255 
			G = (RGB Shr 8 ) And 255
			B = (RGB       ) And 255
			
			R = R * (ColorR / 255.0)
			G = G * (ColorG / 255.0)
			B = B * (ColorB / 255.0)
			
			RGB = (R Shl 16) Or (G Shl 8) Or B
				
			WritePixelFast LoopX, LoopY, RGB, DestBuffer 
		
		Next
	Next
	UnlockBuffer(DestBuffer)

End Function

Blitzplus, why do you hate me so?


Ps:
the reason I need to know the width is so that I can automatically clip the rectangle to the edges of the image... Otherwise Blitz will crash if I specify a rectangle which is too large.


sswift(Posted 2005) [#8]

How about making ssSetFont which takes your font parameters, stores them globally in your RotatedText unit and then sets the font for the current buffer. Then your RotatedText function can retrieve them when it needs to set the same font up for its buffer. You probably already thought of this though?

btw, do you know if DrawBlock is any faster than draw image for non-masked images?

I know you were trying to make a reusable function, but you could easily write a mini function to rotate by 90 degrees only and not use RotateImage function.



I know there are ways I could code AROUND the problems, but that misses the point of my post.

I shouldn't have to code around the problems, and coding around the problems makes messy code which is not as easy to reuse.

All versions of Blitz have had a problem for a very long time where Mark makes all these wonderful functions to set colors, brushes, camera zoom, fog distance, etc, and then he provides no way to get back that information... Which makes coding reusable functions that just work with no muss no fuss, a complete nightmare.

And it's not like it's hard to add these functions. They should have been put in place when the functions that set these values were first added.



btw, do you know if DrawBlock is any faster than draw image for non-masked images?



I don't know. Either one could be faster really. There's too many factors to consider. Like, are the draw operations hardware accelerated? Is it faster to not draw pixels than to draw them? Is the image mostly transparent, or mostly opaque? Is the image being drawn to video memory, or main ram? And if you're drawing the image manually, are you storing the images in RLE format, or are you check to see if each pixel is black before writing it?

The only way to know for sure would be to test, and you'd have to test on multiple hardware configs to be relatively confident in the results.

But I would say that if one is faster than the other, then DrawBlock is highly likely to be the faster of the two.


Grey Alien(Posted 2005) [#9]
Yeah coding round things that should be there is a bummer, I had to do it loads in Delphi.

Goods points about DrawBlock. Go and look at my fade screen code that I just posted (if you want ;-))


Beaker(Posted 2005) [#10]
RequestFont() docs exist here.

DrawBlock is faster than DrawImage.


Grey Alien(Posted 2005) [#11]
where? Not in Blitz 1.4. Downloadable?


Beaker(Posted 2005) [#12]
The docs pak is seperate:
http://www.blitzbasic.com/Community/posts.php?topic=42397


Grey Alien(Posted 2005) [#13]
Thanks Beaker. btw is there a way to check my current version of docs?