Skip to content

Commit 061537c

Browse files
committed
VTF: Add support RGBA, ABGR, I, IA formats
1 parent 744eafd commit 061537c

6 files changed

Lines changed: 189 additions & 99 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class_name VTFDXT extends VTFFrameReader
2+
3+
static func read(vtf: VTFLoader, frame: int, srgb_conversion_method: VTFLoader.SRGBConversionMethod) -> ImageTexture:
4+
var data = PackedByteArray();
5+
var bytes_read := 0;
6+
var is_dxt_1 := vtf.hires_image_format == vtf.ImageFormat.DXT1;
7+
var multiplier = 8 if is_dxt_1 else 16;
8+
var format := vtf.format_map[str(vtf.hires_image_format)] as Image.Format;
9+
var use_mipmaps := not (vtf.flags & vtf.Flags.TEXTUREFLAGS_NOMIP);
10+
11+
frame = vtf.frames - 1 - frame;
12+
13+
for i in range(vtf.mipmap_count):
14+
var mipWidth = max(1, vtf.width >> i);
15+
var mipHeight = max(1, vtf.height >> i);
16+
17+
var mip_size = max(1, mipWidth / 4) * max(1, mipHeight / 4) * multiplier;
18+
19+
vtf.file.seek(vtf.file.get_length() - bytes_read - mip_size - mip_size * frame);
20+
data += vtf.file.get_buffer(mip_size);
21+
22+
bytes_read += mip_size + mip_size * (vtf.frames - 1);
23+
24+
var img := Image.create_from_data(vtf.width, vtf.height, use_mipmaps, format, data);
25+
if not img: return null;
26+
27+
if srgb_conversion_method == vtf.SRGBConversionMethod.DURING_IMPORT:
28+
img.decompress();
29+
img.compress(Image.COMPRESS_S3TC);
30+
31+
vtf.alpha = vtf.flags & vtf.Flags.TEXTUREFLAGS_ONEBITALPHA or vtf.flags & vtf.Flags.TEXTUREFLAGS_EIGHTBITALPHA;
32+
33+
return ImageTexture.create_from_image(img);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class_name VTFFrameReader extends RefCounted
2+
3+
4+
## Base class for reading frames from a VTF file. Each image format should have its own implementation of this class.
5+
static func read(vtf: VTFLoader, frame: int, srgb_conversion_method: VTFLoader.SRGBConversionMethod) -> ImageTexture:
6+
return null;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class_name VTFI8 extends VTFFrameReader
2+
3+
static func read(vtf: VTFLoader, frame: int, srgb_conversion_method: VTFLoader.SRGBConversionMethod) -> ImageTexture:
4+
var data := PackedByteArray();
5+
var bytes_read := 0;
6+
var use_mipmaps := not (vtf.flags & vtf.Flags.TEXTUREFLAGS_NOMIP);
7+
var multiplier := 1 if vtf.hires_image_format == vtf.ImageFormat.I8 else 2;
8+
var output_format := Image.FORMAT_L8 if vtf.hires_image_format == vtf.ImageFormat.I8 else Image.FORMAT_LA8;
9+
10+
frame = vtf.frames - 1 - frame;
11+
12+
for i in range(vtf.mipmap_count):
13+
var mip_width = max(1, vtf.width >> i);
14+
var mip_height = max(1, vtf.height >> i);
15+
var mip_size = mip_width * mip_height * multiplier; # I8 has 1 byte per pixel
16+
17+
vtf.file.seek(vtf.file.get_length() - bytes_read - mip_size - mip_size * frame);
18+
var chunk := vtf.file.get_buffer(mip_size);
19+
20+
data += chunk;
21+
bytes_read += mip_size + mip_size * (vtf.frames - 1);
22+
23+
var img := Image.create_from_data(vtf.width, vtf.height, use_mipmaps, output_format, data);
24+
25+
if not img: return null;
26+
27+
return ImageTexture.create_from_image(img);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class_name VTFRGBA extends VTFFrameReader
2+
3+
static func read(vtf: VTFLoader, frame: int, srgb_conversion_method: VTFLoader.SRGBConversionMethod) -> ImageTexture:
4+
var data := PackedByteArray();
5+
var bytes_read := 0;
6+
var use_mipmaps := not (vtf.flags & vtf.Flags.TEXTUREFLAGS_NOMIP);
7+
var is_abgr := vtf.hires_image_format == vtf.ImageFormat.ABGR8888 || vtf.hires_image_format == vtf.ImageFormat.BGR888;
8+
var is_no_alpha := vtf.hires_image_format >= vtf.ImageFormat.RGB888;
9+
var channels_count := 3 if is_no_alpha else 4;
10+
var output_format := Image.FORMAT_RGB8 if is_no_alpha else Image.FORMAT_RGBA8;
11+
12+
13+
frame = vtf.frames - 1 - frame;
14+
15+
for i in range(vtf.mipmap_count):
16+
var mip_width = max(1, vtf.width >> i);
17+
var mip_height = max(1, vtf.height >> i);
18+
var mip_size = mip_width * mip_height * channels_count; # RGBA8888 has 4 bytes per pixel
19+
20+
vtf.file.seek(vtf.file.get_length() - bytes_read - mip_size - mip_size * frame);
21+
var chunk := vtf.file.get_buffer(mip_size);
22+
23+
if is_abgr: chunk.reverse();
24+
25+
data += chunk;
26+
bytes_read += mip_size + mip_size * (vtf.frames - 1);
27+
28+
var img := Image.create_from_data(vtf.width, vtf.height, use_mipmaps, output_format, data);
29+
30+
if is_abgr:
31+
img.flip_x();
32+
img.flip_y();
33+
34+
if not img: return null;
35+
36+
return ImageTexture.create_from_image(img);

0 commit comments

Comments
 (0)