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/