Problem displaying text

Blitz3D Forums/Blitz3D Beginners Area/Problem displaying text

PowerPC603(Posted 2009) [#1]
Hi,

As some of you know that I'm working on Arkanoid3D, I've come across a problem.
To display some debug-stuff (the duration of the active powerups), I'm using the Text command (see the DebugStuff function).

On my laptop, where I'm developping the game, everything works as expected.
On my other computer, the text doesn't always show.
Most of the time it doesn't show, and sometimes the text "flips" into view for one frame before disappearing again.
Sometimes the text "Bottom: " is shown for a few frames, then disappears again (and it's not the powerup that deactivated) and shows up later again for a few frames.

Even stranger is the scoreblock, where the score and the lives of the player are shown.
For this, I'm using a sprite with a texture that's created in code.
Global ScoreBlock, ScoreTexture
CreateScoreBlock()

Function CreateScoreBlock()
	; Create the sprite
	ScoreBlock = CreateSprite()
	; Position the sprite
	PositionEntity ScoreBlock, 175, 100, 0
	; Scale the sprite
	ScaleSprite ScoreBlock, 20, 20
	; Create a new texture for the scoreblock
	ScoreTexture = CreateTexture(256, 256)
	; Update the scoretexture
	UpdateScore()
	; Apply the texture to the sprite
	EntityTexture ScoreBlock, ScoreTexture
End Function

Function UpdateScore()
	; Set the drawing buffer to the texture
	SetBuffer TextureBuffer(ScoreTexture)
	; Set the background color for the scoreblock
	ClsColor 0, 0, 0 : Cls
	; Set the drawing color to white
	Color 255, 255, 255
	; Print the score and lives onto the texture
	Text 0, 0, "Score: " + Score
	Text 0, 30, "Lives: " + Player\Lives
	If PowerUpActive(CFire) Then Text 0, 60, "Shots left: " + Fire\Instance\Value
	; Reset the drawing buffer to the backbuffer
	SetBuffer BackBuffer()
End Function

Function PlayLevel()
	Local Ball.TBall

	While Not KeyHit(1)
		; Check to see if the left-mouse-button has been hit
		LMBHit = MouseHit(1)

		; Wait for the fps-timer to run out (keep the game at 60 fps)
		WaitTimer(FrameTimer)

		; If the balls haven't been launched yet, check if the player hits the left-mouse-button
		; If the player hits the button, un-parent the balls from the paddle and turn them to a random launch-angle
		LaunchBalls()

		; If the ball(s) have been released, move them depending on their own speed
		; Also perform collision-checking after each ball has been moved
		; to prevent 2 balls hitting one block at once (crashes game if block has value = 1)
		; Also correct the Z-coordinate to prevent balls disappearing into the Z-coordinate
		; If the balls hit a block, shake the block
		MoveBalls()

		; If the Fire powerup is active, shoot the bullets and move them (also perform collision checking)
		ShootBullets()

		; Restore shaken blocks to their default position
		RestoreShakenBlocks()

		; Move the powerups downwards for the player to pickup with his paddle
		; Also perform collision checking if the powerup has hit the paddle and react on it
		MovePowerUps()

		; Let the player move his paddle (and make sure the paddle collides with the walls)
		MovePaddle()

		; Move the lights randomly over the playfield
		MoveLights()

		; Update the sprite which displays the score
		UpdateScore()

		; Render the game world
		RenderWorld

		DebugStuff()

		; Draw everything to the screen
		VWait : Flip False

		; If all destroyable blocks have been destroyed, end the game
		If CheckLevelEnd() = True Then Exit
	Wend
End Function

; This routine is used to debug some things
Function DebugStuff()
	If PowerUpActive(CSteelBalls) = True Then Text 800, 200, "Steel: " + SteelBalls\Instance\Duration
	If PowerUpActive(CLargerPaddle) = True Then Text 800, 230, "Large: " + LargerPaddle\Instance\Duration
	If PowerUpActive(CSmallerPaddle) = True Then Text 800, 260, "Small: " + SmallerPaddle\Instance\Duration
	If PowerUpActive(CDoubleScore) = True Then Text 800, 290, "Double: " + DoubleScore\Instance\Duration
	If PowerUpActive(CGlue) = True Then Text 800, 320, "Glue: " + Glue\Instance\Duration
	If PowerUpActive(CBottomWall) = True Then Text 800, 350, "Bottom: " + BottomWall\Instance\Duration
	Text 800, 400, "Launch: " + BallLaunched
End Function


The texture (ScoreTexture) is a 256x256 texture, created globally.
As you see, nothing is actually wrong with the code, but on the other computer only the score is shown.

Or do I need to reapply the texture on the sprite?

The function CreateScoreBlock is the one I used when the program starts (function is executed once).
The variables ScoreBlock and ScoreTexture are globals.

The sprite is created, positioned and scaled, then the texture is created and applied to the sprite.

Every loop (in the loop PlayLevel) I call the function UpdateScore() to update the texture.
On the laptop, everything is shown on the texture, on the other pc, only the score is shown, not the lives or the shots left.

I even tried VWait : Flip False instead of only Flip and I can't fix it.

If you wanna try it, it's here:
http://users.telenet.be/vge/Arkanoid3D/Arkanoid3D.exe
The zip-files is also there, with full source-code:
http://users.telenet.be/vge/Arkanoid3D/Arkanoid3D.zip


SLotman(Posted 2009) [#2]
If you're writing to a texture, shouldn't you do it *before* renderworld?

Writing directly on screen should be after renderworld for sure, but since you're doing it on a texture, maybe that's the cause?

Also check if the computer supports the texture size you created; maybe you're creating a texture way bigger than the card supports.


PowerPC603(Posted 2009) [#3]
The texture is updated every frame before RenderWorld (in the UpdateScore() function), so that can't be it.
Texture size is 256x256, which most gfx cards should support AFAIK.

If the texture isn't supported, then the texture wouldn't be shown at all.
But it's only partly being displayed (only the score of the player, not the lives). And there's nothing to overlap the sprite which could hide part of the sprite.

I've tried the game on the pc at work (with a crappy gfx card) and it works there perfectly too.

The graphics card on the pc at home (maximum 1 year old) is newer than the one in my laptop (2.5 years old) and has 512Mb RAM onboard (don't remember the card type).

It seems that I need to check the settings on the gfx card at home.

Anyone have some tips what to look for to solve this issue?


_PJ_(Posted 2009) [#4]
I've tried the game on the pc at work (with a crappy gfx card) and it works there perfectly too.


If it works fine on one machine but not on another, it most certainly is related to the hardware of that machine.
It's likely too that older cards can perrform better than newer ones for things like drawing 2D text (even if it is to a 3D texture) because nowadays with DX 9 > the 2D functionality of graphics cards is pretty much left redundant.


I'm not really dsure what can be done (aside from buying different hardware >.< ) but as a very long shot, try setting the EntityFx of the scoreboard sprite to FullBright and DisableFog

EntityFx Sprite,24

It may have absolutelky no effect whatsoeever, but it's just something to try...


Warner(Posted 2009) [#5]
Not sure if this was mentioned allready, but it is safer to use Text to write the text onto the screen, then use CopyRect to copy the text from the backbuffer onto the texture.


PowerPC603(Posted 2009) [#6]
That's also a problem.

The text that's being written to the backbuffer (in the DebugStuff() function) isn't always shown.

It's not like it doesn't work at all (like it would be with a gfx card that doesn't support 2D onto 3D), it's just that some text is written and some isn't.

Like in the UpdateScore() function.

The line
Text 0, 0, "Score: " + Score
is processed properly, as it shows up onto the texture, while the next line
Text 0, 30, "Lives: " + Player\Lives
doesn't show at all onto the texture.

In the DebugStuff() function, is every powerup is active, all lines would need to be printed.
On the laptop and on the pc at work, all lines are properly displayed.
On the homepc, it flickers into view sometimes.

Even if the EntityFx ScoreBlock, 24 would work, there still is the text problem in the DebugStuff() function.

I'll try cutting most code out of the game (by commenting them) in the weekend to see if the problem lies within my code, but I doubt it, since it works perfectly on my laptop and the pc at work.

I don't have any other computer to try it on.
Could some other people here try the game and see if it works fine?


_PJ_(Posted 2009) [#7]
Again, might not help any, but have you tried:

Text 0,0,"Score "+Str(Score%)

For example, to ensure it's writing as a string?


PowerPC603(Posted 2009) [#8]
I've tried everything I could think off, but I'm no closer to a solution on this one.

Even my powerups don't always show the text that's printed on them using the Text command.
When a powerup is generated, the mesh is created, a new texture (size 32x32) is created and drawn and applied to the mesh before anything else happens).

The ScoreBlock is now changed a bit.

I was writing everything to it (Score, Lives, shots left, duration of the powerups) with the Text command, but it got too slow if everything was showing (framerate dropped from 60fps to 33fps).
Now I've replaced the static text ("Score", "Lives", names of the powerups) to an image.
That image is drawn when the game starts up, and every frame, the static text (the parts that must be shown) is CopyRect'ed to the texture.
This works fine both on the laptop and the pc and is alot faster.
But the score-value and lives-value are still Text-commands and are not shown on the pc.

The pc has the nVidia GeForce 8400GS.
I was checking the settings in the nVidia control panel, but I can't get it working.

When the level ends, a sprite is shown with your score.
And when the level starts, another sprite is shown to let the player know which level he has reached.
But on those sprites, the text isn't printed too (but it does work on the laptop) so it can't be the code.

I can't post the entire code as it's too large, but the full source-code is available here:
http://users.telenet.be/vge/Arkanoid3D/Arkanoid3D.zip


Midimaster(Posted 2009) [#9]
only a idea:

can you please remove for testing purposes the if-condition in front of the commands...
	If PowerUpActive(CBottomWall) = True Then Text 800, 350, "Bottom: " + BottomWall\Instance\Duration


to
Text 800, 350, "Bottom: " + BottomWall\Instance\Duration


test this on both computers, and please add a text-command line in the main loop exactly one line before "FLIP".

Text 800, 355, "Test: " + BottomWall\Instance\Duration + "End"
Flip


My idea is, that some other conditions are different on the second computer and not the graphic card causes the problems. Maybe the variable "Duration" is not working, or PowerUpActive(CBottomWall) fails.

What happens if you send the strings to DEBUGLOG? Can you see them there on both computers? Is both running inside the IDE?


PowerPC603(Posted 2009) [#10]
There might be a problem if the BottomWall powerup isn't active, then the instance is deleted, so you can't access the fields (duration).

On the pc, Blitz isn't installed but cannot be a problem to do that.

I'll add a line just before flip and try to catch the problem with Fraps, to see how/if it flickers.


PowerPC603(Posted 2009) [#11]
I've added the line:
Text 800, 500, "This is a test"
right before flip.

So my mainloop now looks like this:
; Play the currently loaded level
Function PlayLevel()
	; Set the text to be printed onto the spritetexture
	Local T$ = "Level: " + Str$(CurrentLevel)
	; Show the sprite for 1 seconds before fading
	Local Counter = 1 * FrameRate
	Local Alpha# = 1.0
	; Create the sprite, position it and draw the given text on it
	Local Sprite = CreateCenterSprite(T$)

	While Not KeyHit(1)
		; Show the sprite with text "Level: xxx" for a certain time and fade it (if it still exists)
		; If the sprite exists
		If Sprite Then
			; Check Counter variable
			If Counter > 0 Then
				; If Counter hasn't reached 0 yet, lower it
				Counter = Counter - 1
			Else
				; If Counter has reached 0
				If Alpha# > 0.0 Then
					; If Alpha hasn't reached 0.0 yet, reduce Alpha (fading the sprite)
					Alpha# = Alpha# - 0.025
					EntityAlpha Sprite, Alpha#
				Else
					; If the Alpha has reached 0.0, free the sprite and reset reference to it
					FreeEntity Sprite : Sprite = 0
				EndIf
			EndIf
		EndIf

		; Check to see if the left-mouse-button has been hit
		LMBHit = MouseHit(1)

		; If the balls haven't been launched yet, check if the player hits the left-mouse-button
		; If the player hits the button, un-parent the balls from the paddle and turn them to a random launch-angle
		LaunchBalls()

		; If the ball(s) have been released, move them depending on their own speed
		; Also perform collision-checking after each ball has been moved
		; to prevent 2 balls hitting one block at once (crashes game if block has value = 1)
		; Also correct the Z-coordinate to prevent balls disappearing into the Z-coordinate
		; If the balls hit a block, shake the block
		MoveBalls()

		; If the Fire powerup is active, shoot the bullets and move them (also perform collision checking)
		ShootBullets()

		; Restore shaken blocks to their default position
		RestoreShakenBlocks()

		; Move the powerups downwards for the player to pickup with his paddle
		; Also perform collision checking if the powerup has hit the paddle and react on it
		MovePowerUps()

		; Let the player move his paddle (and make sure the paddle collides with the walls)
		MovePaddle()

		; Move the lights randomly over the playfield
		MoveLights()

		; Update the sprite which displays the score
		UpdateScore()

		; Make sure the backbuffer is selected
		SetBuffer BackBuffer()

		; Render the game world
		RenderWorld

		; Debug some info
		DebugStuff()

		; Draw everything to the screen
		Flip True

		; If the level has ended (there are no more visible, destructable blocks left), exit the loop (and start the next level)
		If CheckLevelEnd() = True Then Exit
	Wend

	; If the sprite still exists, delete it
	If Sprite Then FreeEntity Sprite
End Function

; This routine is used to debug some things
Function DebugStuff()
	Text 800, 500, "This is a test"
End Function


This text flips onto the screen (for one frame) only when a powerup is generated.
This is very strange.
It seems that it is a problem when changing buffers.
When a powerup is generated, it's texture is also generated and to do that, the game changes the current buffer to the Texture, draws to it and then changes back to the Backbuffer when it has finished drawing the texture.

So when the buffer has changed to a texturebuffer and back to the backbuffer, then the text is written correctly.
When no powerup is generated (so the game doesn't need to change buffers), the text before flip isn't drawn at all.

The duration of the powerups has been changed to a rectangle to show you the duration, because all those text-lines where slowing my laptop down to a crawl.


PowerPC603(Posted 2009) [#12]
I think I've located the problem.

The text before flip was shown every frame when UpdateScore() was commented, so the problem lies there.

It seems the pc has problems writing to texturebuffers.
I've rewritten that function to:
- create an image of size 256x256
- set the buffer to the image (using ImageBuffer)
- draw the text onto this image
- set the buffer back to the backbuffer
- CopyRect the entire image to the texture

Now the text before flip shows every frame, as it's supposed to be.
It seems the pc has problems writing directly to texturebuffers.

That can explain why some powerups were blank too (colored correctly, but without text). It doesn't happen all the time.
I think I'll have to rewrite everything to create images first, draw to them and finally copyrect the image to the textures.

Has anyone seen this behaviour before?


PowerPC603(Posted 2009) [#13]
I've recreated the UpdateScore function to draw to the image first, then copyrect the image to the texture.

Now everything works as expected on the pc too.
Also the powerup-textures seem to be correct now, even though I've done nothing to correct them.

The pc seems to have problems drawing directly onto large textures (256x256 for the ScoreBlock).
But for smaller textures, like the ones for the powerups (max size 64x64) seems to work fine.

Writing to large textures seems to mess up further Text-commands on the pc.
I'll have to remember that next time I create another game when this one is finished.
I've updated the exe and zip online to show the modifications:
http://users.telenet.be/vge/Arkanoid3D/Arkanoid3D.zip
http://users.telenet.be/vge/Arkanoid3D/Arkanoid3D.exe