DXTC in HL2 textures

BlitzMax Forums/BlitzMax Programming/DXTC in HL2 textures

JoshK(Posted 2007) [#1]
Okay, this is a direct loader for HL2 textures. It will load each mipmap level onto the graphics card with compression (if present), without generating an intermediate pixmap. It's pretty much just like DDS.

Thanks to Ryan Greg at Nem's Tools making VTFLib. This does not use his lib, but I learned a lot from it:
Rem
bbdoc: Leadwerks.VTFLoader
EndRem
Module leadwerks.vtfloader

Import leadwerks.texture

Private

Type TTextureLoaderVTF Extends TTextureLoader

	Method LoadTexture:TTexture( stream:TStream )
	
		Return LoadTextureVTF( stream )
	
	End Method
	
End Type

New TTextureLoaderVTF

Public

Rem
bbdoc:
EndRem
Function LoadTextureVTF:TTexture(url:Object)

	Const VTF_IMAGE_FORMAT_RGBA8888=0
	Const VTF_IMAGE_FORMAT_ABGR8888=1
	Const VTF_IMAGE_FORMAT_ARGB8888=11
	Const VTF_IMAGE_FORMAT_BGRA8888=12

	Const IMAGE_FORMAT_RGBA8888 = 0				'<  = Red, Green, Blue, Alpha - 32 bpp
	Const IMAGE_FORMAT_ABGR8888=1					'<  = Alpha, Blue, Green, Red - 32 bpp
	Const IMAGE_FORMAT_RGB888=2					'<  = Red, Green, Blue - 24 bpp
	Const IMAGE_FORMAT_BGR888=3					'<  = Blue, Green, Red - 24 bpp
	Const IMAGE_FORMAT_RGB565=4					'<  = Red, Green, Blue - 16 bpp
	Const IMAGE_FORMAT_I8=5						'<  = Luminance - 8 bpp
	Const IMAGE_FORMAT_IA88=6						'<  = Luminance, Alpha - 16 bpp
	Const IMAGE_FORMAT_P8=7						'<  = Paletted - 8 bpp
	Const IMAGE_FORMAT_A8=8						'<  = Alpha- 8 bpp
	Const IMAGE_FORMAT_RGB888_BLUESCREEN=9			'<  = Red, Green, Blue, "BlueScreen" Alpha - 24 bpp
	Const IMAGE_FORMAT_BGR888_BLUESCREEN=10			'<  = Red, Green, Blue, "BlueScreen" Alpha - 24 bpp
	Const IMAGE_FORMAT_ARGB8888=11					'<  = Alpha, Red, Green, Blue - 32 bpp
	Const IMAGE_FORMAT_BGRA8888=12					'<  = Blue, Green, Red, Alpha - 32 bpp
	Const IMAGE_FORMAT_DXT1=13						'<  = DXT1 compressed format - 4 bpp
	Const IMAGE_FORMAT_DXT3=14						'<  = DXT3 compressed format - 8 bpp
	Const IMAGE_FORMAT_DXT5=15						'<  = DXT5 compressed format - 8 bpp
	Const IMAGE_FORMAT_BGRX8888=16					'<  = Blue, Green, Red, Unused - 32 bpp
	Const IMAGE_FORMAT_BGR565=17					'<  = Blue, Green, Red - 16 bpp
	Const IMAGE_FORMAT_BGRX5551=18					'<  = Blue, Green, Red, Unused - 16 bpp
	Const IMAGE_FORMAT_BGRA4444=19					'<  = Red, Green, Blue, Alpha - 16 bpp
	Const IMAGE_FORMAT_DXT1_ONEBITALPHA=20			'<  = DXT1 compressed format with 1-bit Alpha - 4 bpp
	Const IMAGE_FORMAT_BGRA5551=21					'<  = Blue, Green, Red, Alpha - 16 bpp
	Const IMAGE_FORMAT_UV88=22						'<  = 2 channel format For DuDv/Normal maps - 16 bpp
	Const IMAGE_FORMAT_UVWQ8888=23					'<  = 4 channel format For DuDv/Normal maps - 32 bpp
	Const IMAGE_FORMAT_RGBA16161616F=24				'<  = Red, Green, Blue, Alpha - 64 bpp
	Const IMAGE_FORMAT_RGBA16161616=25				'<  = Red, Green, Blue, Alpha signed with mantissa - 64 bpp
	Const IMAGE_FORMAT_UVLX8888=26					'<  = 4 channel format For DuDv/Normal maps - 32 bpp
	Const IMAGE_FORMAT_I32F=27						'<  = Luminance - 32 bpp
	Const IMAGE_FORMAT_RGB323232F=28				'<  = Red, Green, Blue - 96 bpp
	Const IMAGE_FORMAT_RGBA32323232F=29				'<  = Red, Green, Blue, Alpha - 128 bpp
	Const IMAGE_FORMAT_COUNT=30
	Const IMAGE_FORMAT_NONE = -1
	
	Const TEXTUREFLAGS_POINTSAMPLE = $00000001
	Const TEXTUREFLAGS_TRILINEAR = $00000002
	Const TEXTUREFLAGS_CLAMPS = $00000004
	Const TEXTUREFLAGS_CLAMPT = $00000008
	Const TEXTUREFLAGS_ANISOTROPIC = $00000010
	Const TEXTUREFLAGS_HINT_DXT5 = $00000020
	Const TEXTUREFLAGS_NOCOMPRESS = $00000040
	Const TEXTUREFLAGS_NORMAL = $00000080
	Const TEXTUREFLAGS_NOMIP = $00000100
	Const TEXTUREFLAGS_NOLOD = $00000200
	Const TEXTUREFLAGS_MINMIP = $00000400
	Const TEXTUREFLAGS_PROCEDURAL = $00000800
	Const TEXTUREFLAGS_ONEBITALPHA = $00001000
	Const TEXTUREFLAGS_EIGHTBITALPHA = $00002000
	Const TEXTUREFLAGS_ENVMAP = $00004000
	Const TEXTUREFLAGS_RENDERTARGET = $00008000
	Const TEXTUREFLAGS_DEPTHRENDERTARGET = $00010000
	Const TEXTUREFLAGS_NODEBUGOVERRIDE = $00020000
	Const TEXTUREFLAGS_SINGLECOPY = $00040000
	Const TEXTUREFLAGS_ONEOVERMIPLEVELINALPHA = $00080000
	Const TEXTUREFLAGS_PREMULTCOLORBYONEOVERMIPLEVEL = $00100000
	Const TEXTUREFLAGS_NORMALTODUDV = $00200000
	Const TEXTUREFLAGS_ALPHATESTMIPGENERATION = $00400000
	Const TEXTUREFLAGS_NODEPTHBUFFER = $00800000
	Const TEXTUREFLAGS_NICEFILTERED = $01000000
	Const TEXTUREFLAGS_CLAMPU = $02000000
	
	stream:TStream=ReadStream(url)
	If Not stream Return
	
	'VTF file format specs:
	'http://developer.valvesoftware.com/wiki/VTF#VTF_Layout
	
	Rem
	typedef struct tagVTFHEADER
	{
		char		signature[4];		// File signature ("VTF\0").
		unsigned Int	version[2];		// version[0].version[1] (currently 7.2).
		unsigned Int	headerSize;		// Size of the header struct (16 Byte aligned; currently 80 bytes).
		unsigned Short	width;			// Width of the largest mipmap in pixels. Must be a power of 2.
		unsigned Short	height;			// Height of the largest mipmap in pixels. Must be a power of 2.
		unsigned Int	flags;			// VTF flags.
		unsigned Short	frames;			// Number of frames, If animated (1 For no animation).
		unsigned Short	firstFrame;		// First frame in animation (0 based).
		unsigned char	padding0[4];		// reflectivity padding (16 Byte alignment).
		Float		reflectivity[3];	// reflectivity vector.
		unsigned char	padding1[4];		// reflectivity padding (8 Byte packing).
		Float		bumpmapScale;		// Bumpmap scale.
		unsigned Int	highResImageFormat;	// High resolution image format.
		unsigned char	mipmapCount;		// Number of mipmaps.
		unsigned Int	lowResImageFormat;	// Low resolution image format (always DXT1).
		unsigned char	lowResImageWidth;	// Low resolution image width.
		unsigned char	lowResImageHeight;	// Low resolution image height.
		unsigned Short	depth;			// Depth of the largest mipmap in pixels. Must be a power of 2.  Can be 0 Or 1 For a 2D texture.  v7.2 only.
	} VTFHEADER;
	EndRem
	
	'VTF Header
	If stream.readstring(3)<>"VTF" Return
	stream.readbyte()
	majorversion=stream.readint()
	minorversion=stream.readint()
	headerSize=stream.readint()
	headerstart=stream.pos()
	width=stream.readshort()
	height=stream.readshort()
	flags=stream.readint()
	frames=stream.readshort()
	firstFrame=stream.readshort()
	Local padding:Byte[2,4]
	padding[0,0]=stream.readbyte()
	padding[0,1]=stream.readbyte()
	padding[0,2]=stream.readbyte()
	padding[0,3]=stream.readbyte()
	Local reflectivity#[3]
	reflectivity[0]=stream.readfloat()
	reflectivity[1]=stream.readfloat()
	reflectivity[2]=stream.readfloat()
	padding[1,0]=stream.readbyte()
	padding[1,1]=stream.readbyte()
	padding[1,2]=stream.readbyte()
	padding[1,3]=stream.readbyte()	
	bumpmapScale#=stream.readfloat()
	highResImageFormat=stream.readint()
	mipmapCount=stream.readbyte()
	lowResImageFormat=stream.readint()
	lowResImageWidth=stream.readbyte()
	lowResImageheight=stream.readbyte()
	If majorversion>=7 And minorversion>1 depth=stream.readshort()
	
	stream.seek headerSize'+1
	
	'Low-res image format is always DXTC1 (4 bpp)
	blocksize=((lowResImageWidth+3)/4)*((lowResImageHeight+3)/4)*8
	stream.seek stream.pos()+blocksize
	
	'stream.seek stream.pos()+1
	w=width
	h=height
	For n=0 To mipmapCount-2
		w:/2 ; h:/2
	Next
	
	Select highResImageFormat
		Case IMAGE_FORMAT_RGBA8888
			bpp=32
			srcformat=GL_RGBA
			dstformat=GL_RGBA
		'Case IMAGE_FORMAT_ABGR8888 bpp=32
		Case IMAGE_FORMAT_RGB888
			srcformat=GL_RGB
			dstformat=GL_RGB
			bpp=24
		Case IMAGE_FORMAT_BGR888
			bpp=24
			srcformat=GL_BGR_EXT
			dstformat=GL_RGB
		'Case IMAGE_FORMAT_RGB565 bpp=16
		Case IMAGE_FORMAT_I8
			bpp=8
			srcformat=GL_LUMINANCE8
			dstformat=GL_LUMINANCE8
		Case IMAGE_FORMAT_IA88
			bpp=16
			srcformat=GL_LUMINANCE8_ALPHA8
			dstformat=GL_LUMINANCE8_ALPHA8
		'Case IMAGE_FORMAT_P8 bpp=8
		Case IMAGE_FORMAT_A8
			bpp=8
			srcformat=GL_ALPHA8
			dstformat=GL_ALPHA8
		'Case IMAGE_FORMAT_RGB888_BLUESCREEN bpp=24
		'Case IMAGE_FORMAT_BGR888_BLUESCREEN bpp=24
		'Case IMAGE_FORMAT_ARGB8888 bpp=32
		Case IMAGE_FORMAT_BGRA8888,IMAGE_FORMAT_BGRX8888
			bpp=32
			srcformat=GL_BGRA_EXT
			dstformat=GL_RGBA
		Case IMAGE_FORMAT_DXT1
			bpp=8
			srcformat=GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
			compressed=1
		Case IMAGE_FORMAT_DXT3
			bpp=16
			srcformat=GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
			compressed=1
		Case IMAGE_FORMAT_DXT5
			bpp=16
			srcformat=GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
			compressed=1
		'Case IMAGE_FORMAT_BGR565 bpp=16
		'Case IMAGE_FORMAT_BGRX5551 bpp=16
		'Case IMAGE_FORMAT_BGRA4444 bpp=16
		'Case IMAGE_FORMAT_DXT1_ONEBITALPHA bpp=4
		''Case IMAGE_FORMAT_BGRA5551 bpp=16
		'Case IMAGE_FORMAT_UV88 bpp=16
		'Case IMAGE_FORMAT_UVWQ8888 bpp=32
		'Case IMAGE_FORMAT_RGBA16161616F bpp=64
		'Case IMAGE_FORMAT_RGBA16161616 bpp=64
		'Case IMAGE_FORMAT_UVLX8888 bpp=32
		'Case IMAGE_FORMAT_I32F bpp=32
		'Case IMAGE_FORMAT_RGB323232F bpp=96
		'Case IMAGE_FORMAT_RGBA32323232F bpp=128
		'Case IMAGE_FORMAT_NONE Return Null
		Default Return Null
	EndSelect
	
	tex:TTexture=New TTexture
	tex.bind()

	gltexparameteri tex.target(),GL_TEXTURE_BASE_LEVEL,0
	gltexparameteri tex.target(),GL_TEXTURE_MAX_LEVEL,mipmapCount-1
	
	'Print bpp+" bits per pixel"
	
	For n=0 To mipmapCount-1
		blocksize=((w+3)/4)*((h+3)/4)*bpp
		Local block:Byte[blocksize]
		stream.readbytes(Varptr block[0],blocksize)
		miplevel=mipmapCount-n-1
		If compressed
			glCompressedTexImage2D(tex.target(),miplevel,srcformat,w,h,0,blocksize,Varptr block[0])
		Else
			glTexImage2D(tex.target(),miplevel,dstformat,w,h,0,srcformat,GL_UNSIGNED_BYTE,Varptr block[0])
		EndIf
		'Print miplevel + " - " +w+" x "+h+" : "+tex.width(miplevel)+" x "+tex.height(miplevel)+" - "+blocksize
		w:*2 ; h:*2
	Next
	
	Return tex
EndFunction



Dreamora(Posted 2007) [#2]
Nice

But any reason you put the consts into the function where they will bomb the CPU each time the function is called instead of remaining outside the function? *looking puzzled*
(if you prefer some kind of namespace, put the const and the function in a type for example)


Koriolis(Posted 2007) [#3]
Bomb the CPU? The const statements are entirely compile-time, *nothing* happens at runtime so it really doesn't matter.