DGL https://delphigl.com/forum/ |
|
Valve Texture Format (VTF) Source https://delphigl.com/forum/viewtopic.php?f=19&t=9133 |
Seite 1 von 1 |
Autor: | Stucuk [ Sa Apr 03, 2010 15:58 ] |
Betreff des Beitrags: | Valve Texture Format (VTF) Source |
Note: The unit only returns the first texture at MipMap Level 0 even if the file is animated. It wouldn't be hard to modify the code below so it loads every frame instead of skipping them. function LoadVTFImage(var TexData : TRawTexture; RawData : Pointer; Size : Int64; EXT : PWideChar) : Boolean; TexData stores the result. RawData is the actual VTF file loaded into a Pointer. Size is the size of the RawData. EXT is the Extention of the image, this check could be removed. GL_BGRA is the default format that is returned in the TexData.Data. Code: unit Unit_VTF;
{ VTF - Valve Texture Format This unit is aimed at loading VTF files which are used by Source games (i.e HL2) Its based on http://developer.valvesoftware.com/wiki/VTF Composed by Stuart "Stucuk" Carey This Unit uses parts of Martin Waldegger's DDS Unit for loading the actual textures } interface type TRawTexture = Record Data : Pointer; BPP, Padding : Byte; Width, Height : Word; end; tagVTFHEADER = packed Record Signature : Array [0..3] of Char; // File signature ("VTF\0"). Version : Array [0..1] of Cardinal; // version[0].version[1] (currently 7.1). Headersize : Cardinal; // Size of the header struct (currently 64 bytes). Width, // Width of the largest mipmap in pixels. Must be a power of 2. Height : Word; // Height of the largest mipmap in pixels. Must be a power of 2. Flags : Cardinal; // VTF flags. Frames, // Number of frames, if animated (1 for no animation). FirstFrame : Word; // First frame in animation (0 based). Padding0 : Array [0..3] of Byte; // reflectivity padding (16 byte alignment). Reflectivity : Array [0..2] of Single; // reflectivity vector. Padding1 : Array [0..3] of Byte; // reflectivity padding (8 byte packing). BumpmapScale : Single; // Bumpmap scale. HighResFormat : Integer; // High resolution image format. MipmapCount : Byte; // Number of mipmaps. LowResFormat : integer; // Low resolution image format (always DXT1). LowResWidth, // Low resolution image width. LowResHeight : Byte; // Low resolution image height. B : Byte; // Added to make it 64 bytes long. end; function LoadVTFImage(var TexData : TRawTexture; RawData : Pointer; Size : Int64; EXT : PWideChar) : Boolean; procedure FreeVTFImage(var TexData : TRawTexture); implementation uses Windows,dglOpenGL,SysUtils,Math,Classes; const GL_COMPRESSED_RGB_S3TC_DXT1 = $83F0; GL_COMPRESSED_RGBA_S3TC_DXT1 = $83F1; GL_COMPRESSED_RGBA_S3TC_DXT3 = $83F2; GL_COMPRESSED_RGBA_S3TC_DXT5 = $83F3; IMAGE_FORMAT_NONE = -1; IMAGE_FORMAT_RGBA8888 = 0; IMAGE_FORMAT_ABGR8888 = 1; IMAGE_FORMAT_RGB888 = 2; IMAGE_FORMAT_BGR888 = 3; IMAGE_FORMAT_RGB565 = 4; IMAGE_FORMAT_I8 = 5; IMAGE_FORMAT_IA88 = 6; IMAGE_FORMAT_P8 = 7; IMAGE_FORMAT_A8 = 8; IMAGE_FORMAT_RGB888_BLUESCREEN = 9; IMAGE_FORMAT_BGR888_BLUESCREEN = 10; IMAGE_FORMAT_ARGB8888 = 11; IMAGE_FORMAT_BGRA8888 = 12; IMAGE_FORMAT_DXT1 = 13; IMAGE_FORMAT_DXT3 = 14; IMAGE_FORMAT_DXT5 = 15; IMAGE_FORMAT_BGRX8888 = 16; IMAGE_FORMAT_BGR565 = 17; IMAGE_FORMAT_BGRX5551 = 18; IMAGE_FORMAT_BGRA4444 = 19; IMAGE_FORMAT_DXT1_ONEBITALPHA = 20; IMAGE_FORMAT_BGRA5551 = 21; IMAGE_FORMAT_UV88 = 22; IMAGE_FORMAT_UVWQ8888 = 23; IMAGE_FORMAT_RGBA16161616F = 24; IMAGE_FORMAT_RGBA16161616 = 25; IMAGE_FORMAT_UVLX8888 = 26; TEXTUREFLAGS_POINTSAMPLE = $00000001; TEXTUREFLAGS_TRILINEAR = $00000002; TEXTUREFLAGS_CLAMPS = $00000004; TEXTUREFLAGS_CLAMPT = $00000008; TEXTUREFLAGS_ANISOTROPIC = $00000010; TEXTUREFLAGS_HINT_DXT5 = $00000020; TEXTUREFLAGS_NOCOMPRESS = $00000040; TEXTUREFLAGS_NORMAL = $00000080; TEXTUREFLAGS_NOMIP = $00000100; TEXTUREFLAGS_NOLOD = $00000200; TEXTUREFLAGS_MINMIP = $00000400; TEXTUREFLAGS_PROCEDURAL = $00000800; TEXTUREFLAGS_ONEBITALPHA = $00001000; TEXTUREFLAGS_EIGHTBITALPHA = $00002000; TEXTUREFLAGS_ENVMAP = $00004000; TEXTUREFLAGS_RENDERTARGET = $00008000; TEXTUREFLAGS_DEPTHRENDERTARGET = $00010000; TEXTUREFLAGS_NODEBUGOVERRIDE = $00020000; TEXTUREFLAGS_SINGLECOPY = $00040000; TEXTUREFLAGS_ONEOVERMIPLEVELINALPHA = $00080000; TEXTUREFLAGS_PREMULTCOLORBYONEOVERMIPLEVEL = $00100000; TEXTUREFLAGS_NORMALTODUDV = $00200000; TEXTUREFLAGS_ALPHATESTMIPGENERATION = $00400000; TEXTUREFLAGS_NODEPTHBUFFER = $00800000; TEXTUREFLAGS_NICEFILTERED = $01000000; type TDDSLoadInfo = record compressed: boolean; swap: boolean; palette: boolean; divSize: Cardinal; blockBytes: Cardinal; internalFormat: GLenum; externalFormat: GLenum; typ: GLenum; end; var loadInfoDXT1 : TDDSLoadInfo = (compressed: true; swap: false; palette: false; divsize: 4; blockBytes: 8; internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT1); loadInfoDXT3 : TDDSLoadInfo = (compressed: true; swap: false; palette: false; divsize: 4; blockBytes: 16; internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT3); loadInfoDXT5 : TDDSLoadInfo = (compressed: true; swap: false; palette: false; divsize: 4; blockBytes: 16; internalFormat: GL_COMPRESSED_RGBA_S3TC_DXT5); loadInfoBGR8 : TDDSLoadInfo = (compressed: false; swap: false; palette: false; divsize: 1; blockBytes: 3; internalFormat: GL_RGB8; externalFormat: GL_BGR; typ: GL_UNSIGNED_BYTE); loadInfoBGRA8 : TDDSLoadInfo = (compressed: false; swap: false; palette: false; divsize: 1; blockBytes: 4; internalFormat: GL_RGBA8; externalFormat: GL_BGRA; typ: GL_UNSIGNED_BYTE); loadInfoBGR565 : TDDSLoadInfo = (compressed: false; swap: true; palette: false; divsize: 1; blockBytes: 2; internalFormat: GL_RGB5; externalFormat: GL_BGR; typ: GL_UNSIGNED_SHORT_5_6_5); Procedure SwapY(Pixels: Pointer; xSize, ySize: Integer); var x, y: integer; P1, P2: ^Cardinal; Temp: Cardinal; begin for y:=0 to pred(ySize shr 1) do for x:=0 to pred(xSize) do begin P1 := Pointer(Cardinal(Pixels) + (y*xSize + x)*4); P2 := Pointer(Cardinal(Pixels) + ((ySize-y-1)*xSize + x)*4); Temp := P1^; P1^ := P2^; P2^ := Temp; end; end; Procedure LoadTexture(Var Stream : TMemoryStream; Var Texture : Cardinal; Const Width,Height,CurrMipMap,MipMapCount,TextureType : Integer; Skip : Boolean); var li: ^TDDSLoadInfo; x,y,size : integer; data,pixels: PBytes; begin case TextureType of IMAGE_FORMAT_DXT1 : li := @loadInfoDXT1; IMAGE_FORMAT_DXT3 : li := @loadInfoDXT3; IMAGE_FORMAT_DXT5 : li := @loadInfoDXT5; IMAGE_FORMAT_BGR888 : li := @loadInfoBGR8; IMAGE_FORMAT_BGR565 : li := @loadInfoBGR565; IMAGE_FORMAT_BGRA8888 : li := @loadInfoBGRA8; else Exit; end; x := Width; y := Height; if not Skip then GetMem(pixels, x*y*4); if not Skip then begin glBindTexture(GL_TEXTURE_2D, Texture); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); end; x := Max(x shr CurrMipMap,1); y := Max(y shr CurrMipMap,1); if li.compressed then begin size := max(li.divSize, x ) div li.divSize * max(li.divSize, y) div li.divSize * li.blockBytes; if not Skip then begin GetMem(data, size); Stream.Read(Data^,Size); glCompressedTexImage2D(GL_TEXTURE_2D, CurrMipMap, li.internalFormat, x, y, 0, size, data); glGetTexImage(GL_TEXTURE_2D, CurrMipMap, GL_RGBA, GL_UNSIGNED_BYTE, pixels); SwapY(pixels,x, y); glTexImage2D(GL_TEXTURE_2D, CurrMipMap, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); FreeMem(Data); end else Stream.Seek(Size,1); end else begin size := x * y * li.blockBytes; if not Skip then begin GetMem(data, size); Stream.Read(Data^,Size); if li.swap then glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, CurrMipMap, li.internalFormat, x, y, 0, li.externalFormat, li.typ, data); if li.swap then glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); glGetTexImage(GL_TEXTURE_2D, CurrMipMap, GL_RGBA, GL_UNSIGNED_BYTE, pixels); SwapY(pixels,x, y); glTexImage2D(GL_TEXTURE_2D, CurrMipMap, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); FreeMem(Data); end else Stream.Seek(Size,1); end; if not Skip then FreeMem(pixels); end; Function GetHasAlpha(Format : Integer) : Boolean; begin case Format of 0,1,8,11, 12,13,14, 15,19,20, 21,24,25 : Result := True; else Result := False; end; end; //Note: While VTF's can be animated, for our purposes we just want the first image thats at MipMap 0 function LoadVTFImage(var TexData : TRawTexture; RawData : Pointer; Size : Int64; EXT : PWideChar) : Boolean; var x,y,curmip : integer; MS : TMemoryStream; Header : tagVTFHEADER; TempTexture : Cardinal; Faces : Integer; begin Result := False; if not (Lowercase(WideString(EXT)) = '.vtf') then Exit; MS := TMemoryStream.Create; glGenTextures(1, @TempTexture); try MS.Write(RawData^,Size); MS.Position := 0; MS.Read(Header,SizeOf(Header)); //Future Compatible (Well as future proof as we can get) if Header.Headersize > 64 then MS.Seek(Header.Headersize-64,1); if ((Header.Flags and TEXTUREFLAGS_ENVMAP) = TEXTUREFLAGS_ENVMAP) or (Header.Flags = TEXTUREFLAGS_ENVMAP) then Faces := 6 else Faces := 1; // HasAlpha := GetHasAlpha(Header.HighResFormat); case Header.HighResFormat of IMAGE_FORMAT_DXT1 : ; IMAGE_FORMAT_DXT3 : ; IMAGE_FORMAT_DXT5 : ; IMAGE_FORMAT_BGR888 : ; IMAGE_FORMAT_BGR565 : ; IMAGE_FORMAT_BGRA8888 : ; else // Format not supported so create a blank texture TexData.Data := Nil; TexData.Width := Header.Width; TexData.Height := Header.Height; TexData.BPP := 4; GetMem(TexData.Data, Header.Width*Header.Height*4); FillChar(TexData.Data^,Header.Width*Header.Height*4,0); Result := True; exit; end; LoadTexture(MS,TempTexture,Header.LowResWidth,Header.LowResHeight,0,1,Header.LowResFormat,True); for curmip := Header.MipmapCount-1 downto 0 do begin for x := 0 to Header.Frames-1 do for y := 0 to Faces-1 do begin LoadTexture(MS,TempTexture,Header.Width,Header.Height,curmip,Header.MipmapCount,Header.HighResFormat,not ((X = 0) and (Y = 0) and (curmip = 0))); if (X = 0) and (Y = 0) and (curmip = 0) then begin TexData.Data := Nil; TexData.Width := Header.Width; TexData.Height := Header.Height; TexData.BPP := 4; GetMem(TexData.Data, Header.Width*Header.Height*4); glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, TexData.Data); Result := True; Break; end; end; end; finally glDeleteTextures(1, @TempTexture); MS.Free; end; end; procedure FreeVTFImage(var TexData : TRawTexture); begin if Assigned(TexData.Data) then begin FreeMem(TexData.Data); TexData.Data := Nil; end; end; end. |
Seite 1 von 1 | Alle Zeiten sind UTC + 1 Stunde |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |