Important information: this site is currently scheduled to go offline indefinitely by end of the year.

Bloodrayne .TEX (Xbox type 13)

Get your graphics formats figures out here! Got details for others? Post here!
Post Reply
TheFifthHorseman
ultra-n00b
Posts: 3
Joined: Sun Nov 22, 2020 5:24 pm
Has thanked: 1 time
Been thanked: 1 time

Bloodrayne .TEX (Xbox type 13)

Post by TheFifthHorseman »

I'm looking to decode the textures used in console versions of Bloodrayne to a more readable / editable format. It seems, though, that each of the console versions had its' own (and possibly more than one) variation on the format.
Currently looking at the Xbox format and while I've got the header, palette and image data positions, the texture seems to be encoded in some way that requires translating the pixel coordinates. I have no idea what the algorithm for that should be, any ideas?

What I expect:
Image

What I get:
Image
Acewell
VIP member
VIP member
Posts: 1330
Joined: Wed Nov 05, 2008 12:16 pm
Has thanked: 2710 times
Been thanked: 884 times

Re: Bloodrayne .TEX (Xbox type 13)

Post by Acewell »

likely morton order swizzled, post some samples. :D
TheFifthHorseman
ultra-n00b
Posts: 3
Joined: Sun Nov 22, 2020 5:24 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Bloodrayne .TEX (Xbox type 13)

Post by TheFifthHorseman »

The raw texture for the above picture: https://drive.google.com/file/d/1Nv6LDl ... sp=sharing
The current conversion script (adding to a Type 1 / Type 2 converter script that goes some 15 years back):

Code: Select all

#!/usr/bin/perl  -0777

use open IO=> ':raw';

$opaque= pack "C", 255;
sub addalpha {
	return pack '(a4)*', map {$_.$opaque} unpack '(a3)*', shift;
}
while (<>) {
	unless (($base= $ARGV) =~s/\.TEX$//i) {
		warn "$ARGV has an unrecognized file extension\n";
		next;
	}

	($version, $texType, $W, $H, $x, $mipLevels, $x, $x)= unpack "I*", substr $_, 0, 32;

	if (3 != $version) {
		if (2 != $version) {
			if (6 != $version) {
				if (13 != $version) {
					warn "$ARGV is not a TEX file\n";
					next;
				}
			}
		}
	}
	#$W=$W+$W;
	#$H=$H/2;
	warn "version $version\n";
	warn "texType $texType\n";
	warn "$W x $H\n";
	warn "mip levels $mipLevels\n";
	$suffix= "";
	@shift= 0 .. $mipLevels;
	@W= map {$W >> $_} (@shift,@shift);	# doubled for offsets into texType 2 with miplevels
	@H= map {$H >> $_} (@shift,@shift);
	$pixW= $texType == 3 ?4 :1;
	@off= ($sum= 0);
	for (0..$#W) {
		push @off, $sum+= $W[$_]*$pixW*$H[$_];
	}

	for $mip (0 .. 0) {	
#	for $mip (0 .. $mipLevels) { # We're only interested in the largest version of the texture
		$W= $W[$mip];
		$H= $H[$mip];
		if ($mip) {
			$suffix= -$mip;
		}
		$out= "$base$suffix.bmp";

		# likely BMP values
		$offset= 54;
		$size= $offset + $W*$H*4;
		$ID2= 40;
		$planes= 1;
		$bpp= 32;
		$compression= 0;
		$SizeImage= $W*$H;
		$XPPM= 2834;
		$YPPM= 2834;
		$ColorsUsed= 0;
		$ColorsImportant= 0;

		$colormap= "";
		# override some of these on a per-tex-type basis
		if (1 == $texType || 2 == $texType) {

			@color= @col= unpack "C*", substr $_, 32, 256*3;
			if (2 == $version) {
				@color= @col= unpack "C*", substr $_, 24, 256*3;
			}
			for $n (0..255) {
				# bmp colors are BGR instead of RGB
				for $m (0..2) {
					$color[($n*3)+$m]= $col[($n*3)+2-$m];
				}
			}
			if (1 == $texType) {
				$offset= 54 + 256*4;    # 256 color palette
				$size= $offset+$W*$H;
				$bpp= 8;
				$ColorsUsed= 256;
				$ColorsImportant= 256;
				$colormap= addalpha pack 'C*', @color;
				$texture= pack "(a$W)*", reverse unpack "(a$W)*", substr $_, 800+$off[$mip], $W*$H;
			} else {
				$wh= $W*$H;
				my @image= unpack "C*", pack "(a$W)*", reverse unpack "(a$W)*", substr $_, 800+$off[$mip], $wh;
				my @opacity= unpack "(a1)*", pack "(a$W)*", reverse unpack "(a$W)*", substr $_, 800+$off[$mip+1+$mipLevels], $wh;
				my @rgb= unpack "(a3)*", pack "C*", @color;
				$texture= pack "(a4)*", map {"$rgb[$image[$_]]$opacity[$_]"} 0..($wh-1);
			}
		} elsif (3 == $texType) {
			$W4= $W*4;	# width of scanline
			$texture= pack "(a$W4)*", reverse unpack "(a$W4)*", substr $_, 32+$off[$mip], $W4*$H;
		} elsif (6 == $texType) {
			#PS2 texture format
			@color= @col= unpack "C*", substr $_, 0x38, 256*4;
			
			$CurrOfs = 1;
			for $i (1 .. 255){
				$SwitchI = ($i / 8)%4;
				if    ( 1 == $SwitchI ) { $vSum = 8;  }
				elsif ( 2 == $SwitchI ) { $vSum = -8; }
				else  				 	{ $vSum = 0; }
				$storeAddr = $i + $vSum ;
				$color[($storeAddr*4)+0] = $col[($CurrOfs*4)+0];
				$color[($storeAddr*4)+1] =  $col[($CurrOfs*4)+1];
				$color[($storeAddr*4)+2] =  $col[($CurrOfs*4)+2];
				$color[($storeAddr*4)+3] =  $col[($CurrOfs*4)+3];
				$CurrOfs += 1;
			}
			for $n (0..256*4-1) {
				$col[$n]=$color[$n];
			}
			for $n (0..255) {
				# bmp colors are BGR instead of RGB
				$color[($n*4)+0]= $col[($n*4)+2];
				$color[($n*4)+1]= $col[($n*4)+1];
				$color[($n*4)+2]= $col[($n*4)+0];
				$color[($n*4)+3]= 255;
			}
			
			$offset= 54 + 256*4;    # 256 color palette
			$size= $offset+$W*$H;
			$bpp= 8;
			$ColorsUsed= 256;
			$ColorsImportant= 256;
			$colormap= pack 'C*', @color;
			@texout = @rawtex = unpack "C*", substr $_, (0x38 + 31 + 0x100*4)+$off[$mip], $W*$H;

			$block_location = 0;
			$byte_num = 0;
			$swap_selector = 0;
			$posY = 0;
			$column_location = 0;
			for $y (0..$H-1) {
				for $x (0..$W-1) {
					$block_location = ($y & -16) * $W + ($x & -16) * 2;
					$swap_selector = (( ($y + 2) >> 2) & 0x1) * 4;
					$posY = ((($y  & -4) >> 1) + ($y & 1)) & 0x7;
					$column_location = $posY * $W * 2 + (($x + $swap_selector) & 0x7) * 4;
					$byte_num = (( $y >> 1) & 1) + ( ( $x >> 2) & 2);
					$texout[($y * $W) + $x] = $rawtex[$block_location + $column_location + $byte_num + 1];
				}
			}

			@texrows = @rawtexrows=  unpack "(a$W)*", pack 'C*', @texout;
			$texture= pack "(a$W)*", reverse @texrows;
		} elsif (13 == $texType) {
			#Xbox (original) texture format
			@color= @col= unpack "C*", substr $_, 0x18, 256*4;
			#The palette is BMP-correct as-is
			$offset= 0x18 + 256*4;    # 256 color palette
			$size= $offset+$W*$H;
			$bpp= 8;
			$ColorsUsed= 256;
			$ColorsImportant= 256;
			$colormap= pack 'C*', @color;
			@texout = @rawtex = unpack "C*", substr $_, (0x18 + 0x100*4)+$off[$mip], $W*$H;

			@texrows = @rawtexrows=  unpack "(a$W)*", pack 'C*', @texout;
			$texture= pack "(a$W)*", reverse @texrows;
		}
		else {
			warn "$ARGV: unsupported tex file type: $texType\n";
			next;
		}

		$header= "BM".pack "IssIIIIssIIIIII", $size, 0, 0, $offset, $ID2, $W, $H, $planes, $bpp, $compression, $SizeImage, $XPPM, $YPPM, $ColorsUsed, $ColorsImportant;

		open OUT, "> $out" or die "can't write to $out";

		print OUT $header;
		print OUT $colormap;
		print OUT $texture;

		close OUT;
	}
}
The type 6 support was based on code described in another thread here ( viewtopic.php?p=161964#p162244 ) and works for that, but the unswizzling algorithm isn't applicable for Type 13. When tried, this is the result I get:
Image
User avatar
DKDave
ultra-veteran
ultra-veteran
Posts: 357
Joined: Mon May 06, 2019 6:07 pm
Location: On board the USS Callister
Has thanked: 9 times
Been thanked: 167 times

Re: Bloodrayne .TEX (Xbox type 13)

Post by DKDave »

Have you tried using Turfster's BloodRayne Toolset? It works perfectly with your example:

Image
I see a vision rising, dreary, Fading in as children play twilight games, In the town called Ordinary, An eye of light reveals a gateway to doomsday
TheFifthHorseman
ultra-n00b
Posts: 3
Joined: Sun Nov 22, 2020 5:24 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Bloodrayne .TEX (Xbox type 13)

Post by TheFifthHorseman »

Which version are you using? I've got v3.5BETA5 build 051205-0240, and that one doesn't handle the Xbox textures.

EDIT: Found 3.7 build 190106-1258, that one SOLVED the problem. Thanks!
Post Reply