Texture quality

Blitz3D Forums/Blitz3D Programming/Texture quality

nawi(Posted 2009) [#1]
How can I make the texture quality a variable? I'm talking about lowering the texture resolution. My code doesn't work properly, there's a problem with transparency atleast.

;Loads a texture with error handling
Function gLoadtexture(gfile$,gflags=0,optimize=1)
	gtext = LoadTexture(gfile$,gflags)
	If Main.Settings\LowQualityTexture > 0 And optimize=1 Then
		For a = 1 To Main.Settings\LowQualityTexture
			newwidth = TextureWidth(gtext)*0.5
			newheight = TextureHeight(gtext)*0.5
			If newwidth = 0 Then newwidth = 1
			If newheight = 0 Then newheight = 1
			newtexture = CreateTexture(newwidth,newheight,flags)
			newimage = CreateImage(TextureWidth(gtext),TextureHeight(gtext))
			CopyRect 0,0,TextureWidth(gtext),TextureHeight(gtext),0,0,TextureBuffer(gtext),ImageBuffer(newimage)
			ScaleImage newimage,0.5,0.5
			SetBuffer TextureBuffer(newtexture)
			DrawImage newimage,0,0
			SetBuffer BackBuffer()
			FreeTexture gtext
			gtext = newtexture
		Next
	EndIf
	If Not gtext Then RuntimeError "Error loading texture " + gfile$
	Return gtext
End Function



FlagDKT(Posted 2009) [#2]
What's the problem?


nawi(Posted 2009) [#3]
Well, transparency is removed from the textures.


Vorderman(Posted 2009) [#4]
I don't think Blitz images support an alpha channel - they rely on black to be the mask colour, so when you copy to an image for rescaling you are losing the alpha channel.

I found it much easier to just save copies of the textures scaled to the required sizes in the graphics package rather than try to rescale them all in Blitz, then just get your program to load the right size texture dep. upon the texture quality option the user has set.


nawi(Posted 2009) [#5]
I wan't several texture quality options, and that would take too much time and disk space, plus I would need to have several models which would load the different texture file.


Yasha(Posted 2009) [#6]
This seems to work:

Function ResizeTexture(srctex,scalex#,scaley#,flags)
	origx=TextureWidth(srctex):origy=TextureHeight(srctex)
	
	rgbimg=CreateImage(origx,origy)								;copy RGB
	CopyRect 0,0,origx,origy,0,0,TextureBuffer(srctex),ImageBuffer(rgbimg)
	
	alfimg=CreateImage(origx,origy)								;copy alpha
	LockBuffer TextureBuffer(srctex):LockBuffer ImageBuffer(alfimg)
	For x=0 To origx-1
		For y=0 To origy-1
			WritePixelFast x,y,(ReadPixelFast(x,y,TextureBuffer(srctex)) And $FF000000) Shr 24,ImageBuffer(alfimg)
		Next
	Next
	UnlockBuffer TextureBuffer(srctex):UnlockBuffer ImageBuffer(alfimg)
	
	ScaleImage rgbimg,scalex,scaley
	ScaleImage alfimg,scalex,scaley
	
	newx=origx*scalex:newy=origy*scaley
	newtex=CreateTexture(newx,newy,flags)
	LockBuffer TextureBuffer(newtex):LockBuffer ImageBuffer(rgbimg):LockBuffer ImageBuffer(alfimg)
	For x=0 To newx-1
		For y=0 To newy-1
			WritePixelFast x,y,(ReadPixelFast(x,y,ImageBuffer(alfimg)) Shl 24) Or (ReadPixelFast(x,y,ImageBuffer(rgbimg)) And $00FFFFFF),TextureBuffer(newtex)
		Next
	Next
	UnlockBuffer TextureBuffer(newtex):UnlockBuffer ImageBuffer(rgbimg):UnlockBuffer ImageBuffer(alfimg)
	
	FreeTexture srctex		;Or not, as the case may be
	FreeImage alfimg
	FreeImage rgbimg
	Return newtex
End Function


Images can't store alpha in the alpha channel - so instead you can store it in the blue channel of a second image, scale both, and combine them again.


Ross C(Posted 2009) [#7]
Just Write and Read pixel fast, and copy the alha channel?


nawi(Posted 2009) [#8]
Thanks, Yasha, that works perfectly! I'll use the function in my game StuntMoto probably.
EDIT:
By the way, if I get a texture from a entity using:
Surface = GetSurface(gmesh,1)
SurfaceBrush = GetSurfaceBrush(Surface)
SurfaceTexture = GetBrushTexture(SurfaceBrush)
Then resize it and apply the texture to the entity, will the original entity texture get deleted from memory or is it a memory leak?


nawi(Posted 2009) [#9]
Bah, I'm having trouble in applying the resize code to the mesh (it works fine for textures).
;Loads a mesh with error handling
Function gLoadmesh(gfile$,gparent=0)
	gmesh = LoadMesh(gfile$,gparent)
	If Not gmesh Then RuntimeError "Error loading mesh " + gfile$
	If Main.Settings\LowQualityTexture > 0 Then
		Surface = GetSurface(gmesh,1)
		If Not Surface Then RuntimeError "Surface not found in " + gfile$
		SurfaceBrush = GetSurfaceBrush(Surface)
		;SurfaceBrush = GetEntityBrush(gmesh)
		If Not SurfaceBrush Then RuntimeError "Brush not found in " + gfile$
		SurfaceTexture = GetBrushTexture(SurfaceBrush)
		If Not SurfaceTexture Then RuntimeError "Texture not found in " + gfile$
		DebugLog TextureName$(SurfaceTexture)
		DebugLog gfile$
		If SurfaceTexture Then
			For a = 1 To Main.Settings\LowQualityTexture
				DebugLog "Texture start"
				SurfaceTexture = ResizeTexture(SurfaceTexture,0.5,0.5)
			Next
		EndIf
		EntityTexture gmesh,SurfaceTexture
		FreeBrush SurfaceBrush 
	EndIf
	Return gmesh
End Function

I get memory access error in the ResizeTexture function at the line "origx=TextureWidth(srctex)", so basically the texture is not found for some reason :o.


Yasha(Posted 2009) [#10]
Wow, that's weird.

Are you sure your texture exists, or that the path is correct? Because my test didn't cause that error if the texture existed (but did, when the texture named in the b3d didn't exist).

EDIT: The line SurfaceTexture = GetBrushTexture(SurfaceBrush) still apparently returns something even when the texture doesn't exist, so your check won't work.

Here's my test - a generic empty project with the two functions in the thread above, gLoadMesh and ResizeTexture. The b3d is Psionic's zombie, which comes free with PaceMaker.



The mesh is loaded, positioned, retextured with the new texture - and then the Z-ordering is completely wrecked? WTF?

This doesn't happen if you comment out ResizeTexture from gLoadMesh. I have no idea what causes this... perhaps it's a memory leak as the texture is a different size from what the brush expected to free?

EDIT 2: Doesn't happen if the resized texture is not an alpha texture. Hum. Not a memory leak then.


Warner(Posted 2009) [#11]
I believe that when using Alpha, z-ordering is disabled: http://blogs.msdn.com/shawnhar/archive/2009/02/18/depth-sorting-alpha-blended-objects.aspx



Kryzon(Posted 2009) [#12]
I wonder how games like Warcraft 3 do it. The lowest you set the "Texture Quality" setting, the more you can see the JPEG compression being applied to the texture.


Ross C(Posted 2009) [#13]
I believe they have all the textures already downscaled on the hard disc. Also, when z-ordering is scaped with alpha, the poly's are sorted by creation. I believe the ones created first, are displayed on top.


Warner(Posted 2009) [#14]
You can enable z-sorting by using WBuffer true, however, it wouldn't really solve anything.


Kryzon(Posted 2009) [#15]
But Ross, isn't there a way to control how much compression will be applied to the JPEG (just like softwares like Photoshop do it, where you can set up how much quality\compression you want)?

Perhaps they compress to that much that the user set up, and then load that up in memory the way it is.

That way for every texture in the game there is one version with perfect quality, and the lowest you set up the texture quality, the more compression will be applied to the instance of the texture that will be loaded and mapped. It's how I think they do it.