To TileImage or Not To TileImage

BlitzMax Forums/BlitzMax Programming/To TileImage or Not To TileImage

ATM Im doing a parallax effect with TileImage on a 800x600 screen.

Ive got 4 images all 800x600:

Background - jpg
1st Mountains - png
2nd Mountains -png
Ground/Tress - png

Should I continue using tileimage or should I make the images smaller and draw multiple of them to create the effect?

Thanks!

I wouldn't use TileImage. Its viewport dependent and you can't rely on that working on all hardware.

Thanks for that Gfk....

I knew that you cant rely on viewports, but didnt know that about TileImage...

Well, TileImage fills the current viewport with a tiled image. As I understand it, the problem arises when you're using a viewport that is smaller than the display area, as the bounds of the viewport are ignored on some hardware.

If you're just filling the entire screen then you *might* be OK - anybody confirm this is correct (or not)?

However, just as a side-note, you may want to redesign your images so they can be split into 128x128 tiles, and draw it that way. A lot of hardware gets all funny over non-square, non-base 2 textures. Plus the way you've done it, is essentially four 1024x1024 textures which equates to 16MB or thereabouts of graphics memory, which is probably inefficient.

Cool, thanks again Gfk.

Now does any know of a good image splitter software which keeps alpha for pngs?

EDIT: Found out the Paint Shop Pro does a nice job with its Export > Image Slicer ;-)

EDIT 2: What Im I doing!?! Why dont I just load the images up in an animation and split it that way!

Was just gonna post what GfK said about four 800x600 images = 1024x1024 x4 bytes x4 images = 16MB of VRAM.

What Im I doing!?! Why dont I just load the images up in an animation and split it that way!
Yep. That's what I'm doing! ;)

However you'll soon notice (if not already) that 128 into 800 doesn't go. Nor does 64. Or 256. I'd resize your image so you can divide it by 128 or whatever, then scale it slightly to fit the screen.

My next game is going to be logically based on 640x480 or 1024x678 to avoid this issue. Although I said that last time and I still forgot. :)

What about "cheating" and making the images 100x100, so I have 8 columns and 6 rows? I know its still not efficient, but wont the images just round up to 128x128...

So that means I would have:

128 * 128 * 4 bytes * (( 8 * 6 ) * 4) = 12582912 = 13MB of VRAM

Hmmm... maybe I'll just have 3 layers.... 9MB....

If you let the API resize to 128x128 then you'll need to enable filtering when you draw or else the scaling will be ugly and pixelly. This is fine, except that you'll need mipmaps to do this, and this will use up approximately 1.5 times the normal amount of VRAM. So 13 will become ~ 20, which is more than the 16 you'd use to load the bigger images.

Im not scaling them after spliting them into 100x100 or it wouldnt fit on the 800x600 screen nicely... I just meant the image would round up in VRAM

Possible problem: if you scrolling using floating point coords do you get any ugly join lines where the anti-aliasing at fractional coords is occuring?

I havent noticed any ugly join lines... yet. It seems to work quite nice.

I'll post an example tonight....

Im not scaling them after spliting them into 100x100 or it wouldnt fit on the 800x600 screen nicely... I just meant the image would round up in VRAM

Sure you are. If you're drawing them at size 100x100 and they're actually 128x128 then either you're scaling them or the UV coordinates are adjusted. In the former case, you most definitely need mipmaps, in the latter, you may or may not, but I suspect you will because it's not a precise pixel perfect operation.

Ok... so even if the image size is 100x100 and the memory space it uses is 128x128, then Im scaling them still even though I'm not using the setscale command?

Im loading the image like this (test .pngis 800x,600):

image:TImage = loadanimimage("test.png",100,100,0,48)

and drawing like this:

Drawimage image , 100, 100, 5

Well, I'm not 100% positive what BlitzMax does, but I think it adjusts the UV coordinates to fit. So you're not really scaling, but where those UV coordinates have been adjusted - and because of floating point inaccuracy - that UV coordinate is probably not exactly on a pixel border any more. So the scale is being very slightly offset, and I don't know if it will be enough to make a difference. But if it is ugly, you'll need to load the image with mip maps included.

Thats cool, thanks for the info.

Heres the quick example:


SuperStrict 

Const screenwidth:Int = 800
Const screenheight:Int = 600

Graphics screenwidth,screenheight,0


Global fighterImage:TImage = LoadImage("fighter.png")
Global bgimage:TImage = LoadAnimImage("bg.png" , 100 , 100 , 0 , 48)
Global bg1image:TImage = LoadAnimImage("bg1.png" , 100 , 100 , 0 , 48) 
Global bg2image:TImage = LoadAnimImage("bg1.jpg" , 100 , 100 , 0 , 48) 

Global bgTiles:Int[8 , 6]
Global bg1Tiles:Int[8 , 6]
Global bg2Tiles:Int[8 , 6]
Global counter:Int = 0

Global bx# = 0 , bx1# = 0, bx2# = 0
Global px# = 100 , py# = 100
Global dx# = 0 , dy# = 0


For Local j:Int = 0 To 5
	For Local i:Int = 0 To 7
		bgTiles[i , j] = counter
		bg1Tiles[i , j] = counter
		bg2Tiles[i , j] = counter
		counter:+1
	Next
Next


While KeyDown(KEY_ESCAPE) = False
	
	logic() 
	draw()
	
Wend

Function logic()
	controlFighter() 
	moveBackground()
End Function	

Function draw() 
	Cls
		drawBackgrounds() 
		drawFighter() 
	Flip	
End Function

Function controlFighter()
	Local eex:Float
	Local eey:Float
	Local ddx:Float
	Local ddy:Float
	
	Local speed:Float = 0.2
	
	eex = MouseX()
	eey = MouseY()
	
	ddx = (eex - px)
	ddy = (eey - py)
	
	Local dist:Float = Sqr(ddx * ddx + ddy * ddy)
	ddx:/dist * speed
	ddy:/dist * speed
	dx = ddx
	dy = ddy	
	
	If PointInSpot(px, py, eex, eey, 3) Then
		dx = 0; dy = 0
	End If	
	
	px:+dx
	py:+dy	
End Function

Function drawFighter() 	
	DrawImage fighterImage, px, py
End Function


Function moveBackground()
	bx:- 2
	bx1:- 1
	bx2:- 0.5	
	If bx < - screenwidth bx = 0	
	If bx1 < - screenwidth bx1 = 0	
	If bx2 < - screenwidth bx2 = 0		
End Function

Function drawBackgrounds()

	For Local i:Int = 0 To 7
		For Local j:Int = 0 To 5
			DrawImage bg2image, bx2 + i * 100, j * 100, bgTiles[i, j]
			DrawImage bg2image, bx2 + screenwidth + i * 100, j * 100, bgTiles[i, j]			
		Next
	Next	

	For Local i:Int = 0 To 7
		For Local j:Int = 0 To 5
			DrawImage bg1image, bx1 + i * 100, j * 100, bgTiles[i, j]
			DrawImage bg1image, bx1 + screenwidth + i * 100, j * 100, bgTiles[i, j]			
		Next
	Next	


	For Local i:Int = 0 To 7
		For Local j:Int = 0 To 5
			DrawImage bgimage , bx + i * 100 , j * 100 , bgTiles[i , j]
			DrawImage bgimage, bx + screenwidth + i * 100, j * 100, bgTiles[i, j]
		Next
	Next

End Function	

Function PointInSpot:Int(x1:Float, y1:Float, x2:Float, y2:Float, radius:Float)
	Local dx:Float = x2 - x1
	Local dy:Float = y2 - y1
	Return Sqr(dx * dx + dy * dy) <= radius
EndFunction


http://therevillsgames.googlepages.com/parallax.zip

Its a lot smoother in GA's Framework ;-)