Need some help with S3TC

Started by
8 comments, last by Tanasoo 16 years, 8 months ago
Hello, I'm looking for some information on the DXT file structure. I have been looking all over the Internet and I have managed to get a basic understanding of how the compression works, but I haven't had much luck with more advanced details, such as the algorithms used. What I'm trying to do is make an application that will read DDS files and output them to some generic format such as BMP. This is mostly so I can learn exactly how the format works, but also for some practical coding practice. So basically what I want is some information to help me take the raw bits and convert them into colored pixels. Some sort of decompression algorithm. Thanks in advance! :)
Advertisement
The DirectX documentation describes the DDS format in enough detail that it is possible to write a DDS reader. In the "index" control of the DX docs, type in "Compressed Texture Formats".

To implement a DDS writer, you need to decide on a compression algorithm. A brief summary of these is from Simon Brown. I have implemented the "range fit" algorithm and find it sufficient in quality. Although the description mentions "principal axes" (i.e. eigendecomposition of a matrix), I used the Power Method for finding the principal axis associated with the largest eigenvalue of a covariance matrix. In the end, the compression is simple to implement.

And with a little extra work, you can get this to work on big endian machines (PPC Mac, XBox360, PS3) as well as on little endian machines.

The DirectX documentation is clear enough that you can construct the RGB/RGBA color value from the compressed data at location (x,y) in the image.
OK, thanks!

I did a quick scan over the docs, and it looks like just what I was hoping for :)
I guess I'm a little slow on this. How exactly is the color data stored in the 16 bits? What would be the value for say (255 0 0) or (0 255 0)?

Thanks for the help.
I just coded up a DDS decoder (public domain). The page is here, download soil.zip check in the src directory. The code you want is in the file "stb_image.c" (modified from Sean's original version to load TGA and DDS images), down near the bottom (just search for "dds"). There is also a DXT1/5 compressor in the "image_DXT.c" file. My code isn't heavily documented, but it's a working implementation, at least [8^)

HTH,
OK, thanks. That should help allot. It may take me a while to decipher because I don't know much about C. But don't worry, if I need help, you'll see it here ;)
I think I'm finally starting to get this! :)

I'm going to "think out loud" if anyone could tell me how I'm going that would be great.

SO, we have our 16 bit color one and it is 5:6:5 RGB. Now in order to get the each component I'll use a & bitmask (1111100000000000 R) (0000011111100000 G) (0000000000011111 B). Then I'll use a >> byteshift for R and G (11 and 5) ot get the lsb in the right spot.

So now I'm assuming that there are 32 colors for R and B and 64 for G. So to get the color in the range of 0-255, I would need to get the decimal value for the component, multiply it by 8 and subtract 1. And for G I would do the same, except 4 not 8. Well, it makes sense in my head, but when i try it on a test image it is slightly off...

I have a 4x4 DXT1 image, I saved it in PhotoShop via the Nvidia plugin. Without the header the file contains the following data:

0948 CC66 00A5 00A5

I'm reading it as big endian in my hex editor and it looks like the R value is 01001 G is 000000 and B is 01001 for the first color. Using the above method I converted it to 0-255 and it gave me a value of (72 0 72) RGB. The only problem is, when I open the file in photoshop, there are three colors and that isn't one of them... The colors are (74 0 74) for the whole top row, and third row. (99 219 99) for first half of the second and fourth rows, and (87 110 87) for the rest. ( 74 0 74 ) is close to what I got, am I just doing my math wrong?

Thanks for any help!
OK, when converting bit depths things can get a bit more tricky than just doing some bit shifting. For example you want to convert the 8 bit number 255 to a 5 bit integer...

255 >> 3 = 31

now converting it back

31 << 3 = 248

So just doing the bit shift is insufficient to expand (or contract, really) from one bit depth to another. In your case, you have a 5 bit red value of 9, that you want to restore to its original 8 bit value...just doing 9 << 3 yields 72. Take a look at the function "convert_bit_range()" in my code, it does something like this:

we have c = 9, in a 5 bit number, range 0-31
we want to convert that to a 8 bit number, range 0-255
temp = c * 255 + (32 / 2) = 2311
converted = (temp/32 + temp) / 32 = (72 + 2311) / 32 = 74

The math is just a bit convoluted because it is working all with integers, which are truncated after each division. This function takes care of changing the bit depth of an integer and getting it to scale correctly over the full range.
Ah I see. I had a feeling there was something more complex involved. Thanks a ton!
It's me again, and my hunger for knowledge still isn't sated!

Not content with just reading DXTC I have begun implementing ATI's 3DC compression, too. As most of you know, 3DC only stores two of the three color channels and calculates the third. Again, my method is close, but slightly off sometimes and I have a feeling it has to do with my math again.

I'm taking samples of pixels from a normal map in Photoshop and trying to calculate the blue channel based only on the red and green as a test.
Here is what I'm doing now:

RGIN = #(RColor, GColor) // array with the two input colors R and G
RVec = ((((RGIN[1] - .5) *2) /255) - 1) // converting R to a vector (-1 to +1)
GVec = ((((RGIN[2] - .5) *2) /255) - 1) // same with green
ZVec = sqrt (1 - ((RVec * RVec) + (GVec * GVec))) // trying to calculate the Z vector
BOUT = ((((ZVec + 1) * 255) / 2) + .5) // Convert the Z vector back to 0-255


If I try this on a plain flat surface (R 127 G 127) I get a ZVec value of 0.999938 and a BOUT value of 255.492 and that is so close to 255 I believe I am on the right track, but If I try it on other pixels, the blue channel is sometimes off by up to about 10...

Thanks again in advance! And I really appreciate you guys putting up with my relative ignorance on these matters! I'm a 3D artist by trade, but I'm trying to learn some of the more technical aspects of the art I create, as well as some coding skills :)

This topic is closed to new replies.

Advertisement