|
|
#include <stdint.h> |
|
|
#include <stddef.h> |
|
|
|
|
|
/* |
|
|
DXT1/DXT3/DXT5 texture decompression |
|
|
|
|
|
The original code is from Benjamin Dobell, see below for details. Compared to |
|
|
the original this one adds DXT3 decompression, is valid C89, and is x64 |
|
|
compatible as it uses fixed size integers everywhere. It also uses a different |
|
|
PackRGBA order. |
|
|
|
|
|
--- |
|
|
|
|
|
Copyright (c) 2012, Matth<EFBFBD>us G. "Anteru" Chajdas (http://anteru.net) |
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
|
this software and associated documentation files (the "Software"), to deal in |
|
|
the Software without restriction, including without limitation the rights to |
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|
|
of the Software, and to permit persons to whom the Software is furnished to do |
|
|
so, subject to the following conditions: |
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all |
|
|
copies or substantial portions of the Software. |
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
SOFTWARE. |
|
|
|
|
|
--- |
|
|
|
|
|
Copyright (C) 2009 Benjamin Dobell, Glass Echidna |
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
|
this software and associated documentation files (the "Software"), to deal in |
|
|
the Software without restriction, including without limitation the rights to |
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|
|
of the Software, and to permit persons to whom the Software is furnished to do |
|
|
so, subject to the following conditions: |
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all |
|
|
copies or substantial portions of the Software. |
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
SOFTWARE. |
|
|
|
|
|
--- |
|
|
*/ |
|
|
static uint32_t PackRGBA (uint8_t r, uint8_t g, uint8_t b, uint8_t a) |
|
|
{ |
|
|
return r | (g << 8) | (b << 16) | (a << 24); |
|
|
} |
|
|
|
|
|
static void DecompressBlockDXT1Internal (const uint8_t* block, |
|
|
uint32_t* output, |
|
|
uint32_t outputStride, |
|
|
int transparent0, int* simpleAlpha, int *complexAlpha, |
|
|
const uint8_t* alphaValues) |
|
|
{ |
|
|
uint32_t temp, code; |
|
|
|
|
|
uint16_t color0, color1; |
|
|
uint8_t r0, g0, b0, r1, g1, b1; |
|
|
|
|
|
int i, j; |
|
|
|
|
|
color0 = *(const uint16_t*)(block); |
|
|
color1 = *(const uint16_t*)(block + 2); |
|
|
|
|
|
temp = (color0 >> 11) * 255 + 16; |
|
|
r0 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color0 & 0x07E0) >> 5) * 255 + 32; |
|
|
g0 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color0 & 0x001F) * 255 + 16; |
|
|
b0 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
temp = (color1 >> 11) * 255 + 16; |
|
|
r1 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color1 & 0x07E0) >> 5) * 255 + 32; |
|
|
g1 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color1 & 0x001F) * 255 + 16; |
|
|
b1 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
code = *(const uint32_t*)(block + 4); |
|
|
|
|
|
for (j = 0; j < 4; ++j) { |
|
|
for (i = 0; i < 4; ++i) { |
|
|
uint32_t finalColor, positionCode; |
|
|
uint8_t alpha; |
|
|
|
|
|
finalColor = 0; positionCode = (code >> 2*(4*j+i)) & 0x03; |
|
|
alpha = alphaValues [j*4+i]; |
|
|
|
|
|
if (color0 > color1) { |
|
|
switch (positionCode) |
|
|
{ |
|
|
case 0: |
|
|
finalColor = PackRGBA(r0, g0, b0, alpha); |
|
|
break; |
|
|
case 1: |
|
|
finalColor = PackRGBA(r1, g1, b1, alpha); |
|
|
break; |
|
|
case 2: |
|
|
finalColor = PackRGBA((2*r0+r1)/3, (2*g0+g1)/3, (2*b0+b1)/3, alpha); |
|
|
break; |
|
|
case 3: |
|
|
finalColor = PackRGBA((r0+2*r1)/3, (g0+2*g1)/3, (b0+2*b1)/3, alpha); |
|
|
break; |
|
|
} |
|
|
} else { |
|
|
switch (positionCode) { |
|
|
case 0: |
|
|
finalColor = PackRGBA(r0, g0, b0, alpha); |
|
|
break; |
|
|
case 1: |
|
|
finalColor = PackRGBA(r1, g1, b1, alpha); |
|
|
break; |
|
|
case 2: |
|
|
finalColor = PackRGBA((r0+r1)/2, (g0+g1)/2, (b0+b1)/2, alpha); |
|
|
break; |
|
|
case 3: |
|
|
if(transparent0) alpha=0; |
|
|
finalColor = PackRGBA(0, 0, 0, alpha); |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
if(!alpha) |
|
|
*simpleAlpha = 1; |
|
|
else if(alpha<0xff) |
|
|
*complexAlpha = 1; |
|
|
|
|
|
output [j*outputStride + i] = finalColor; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
static void DecompressBlockDXT1InternalRGB(const uint8_t* block, uint8_t* output, uint32_t outputStride) |
|
|
{ |
|
|
uint32_t temp, code; |
|
|
|
|
|
uint16_t color0, color1; |
|
|
uint8_t r0, g0, b0, r1, g1, b1; |
|
|
|
|
|
int i, j; |
|
|
|
|
|
color0 = *(const uint16_t*)(block); |
|
|
color1 = *(const uint16_t*)(block + 2); |
|
|
|
|
|
temp = (color0 >> 11) * 255 + 16; |
|
|
r0 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color0 & 0x07E0) >> 5) * 255 + 32; |
|
|
g0 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color0 & 0x001F) * 255 + 16; |
|
|
b0 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
temp = (color1 >> 11) * 255 + 16; |
|
|
r1 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color1 & 0x07E0) >> 5) * 255 + 32; |
|
|
g1 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color1 & 0x001F) * 255 + 16; |
|
|
b1 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
code = *(const uint32_t*)(block + 4); |
|
|
|
|
|
for (j = 0; j < 4; ++j) { |
|
|
for (i = 0; i < 4; ++i) { |
|
|
uint8_t positionCode, finalR, finalG, finalB; |
|
|
|
|
|
positionCode = (code >> 2*(4*j+i)) & 0x03; |
|
|
|
|
|
if (color0 > color1) { |
|
|
|
|
|
switch (positionCode) { |
|
|
case 0: |
|
|
finalR = r0; finalG = g0; finalB = b0; |
|
|
break; |
|
|
case 1: |
|
|
finalR = r1; finalG = g1; finalB = b1; |
|
|
break; |
|
|
case 2: |
|
|
|
|
|
finalR = (2*r0+r1)/3; finalG = (2*g0+g1)/3; finalB = (2*b0+b1)/3; |
|
|
break; |
|
|
case 3: |
|
|
finalR = (r0+2*r1)/3; finalG = (g0+2*g1)/3; finalB = (b0+2*b1)/3; |
|
|
break; |
|
|
} |
|
|
} else { |
|
|
switch (positionCode) { |
|
|
case 0: |
|
|
finalR = r0; finalG = g0; finalB = b0; |
|
|
break; |
|
|
case 1: |
|
|
finalR = r1; finalG = g1; finalB = b1; |
|
|
break; |
|
|
case 2: |
|
|
finalR = (r0+r1)/2; finalG = (g0+g1)/2; finalB = (b0+b1)/2; |
|
|
break; |
|
|
case 3: |
|
|
finalR = finalG = finalB = 0; |
|
|
break; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
output[j*outputStride*3 + i*3] = finalR; |
|
|
output[j*outputStride*3 + i*3+1] = finalG; |
|
|
output[j*outputStride*3 + i*3+2] = finalB; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
void DecompressBlockDXT1(): Decompresses one block of a DXT1 texture and stores the resulting pixels at the appropriate offset in 'image'. |
|
|
|
|
|
uint32_t x: x-coordinate of the first pixel in the block. |
|
|
uint32_t y: y-coordinate of the first pixel in the block. |
|
|
uint32_t width: width of the texture being decompressed. |
|
|
const uint8_t *blockStorage: pointer to the block to decompress. |
|
|
uint32_t *image: pointer to image where the decompressed pixel data should be stored. |
|
|
*/ |
|
|
void DecompressBlockDXT1(uint32_t x, uint32_t y, uint32_t width, |
|
|
const uint8_t* blockStorage, |
|
|
int transparent0, int* simpleAlpha, int *complexAlpha, |
|
|
uint32_t* image) |
|
|
{ |
|
|
|
|
|
static const uint8_t const_alpha [] = { |
|
|
255, 255, 255, 255, |
|
|
255, 255, 255, 255, |
|
|
255, 255, 255, 255, |
|
|
255, 255, 255, 255 |
|
|
}; |
|
|
|
|
|
|
|
|
if( transparent0 ) |
|
|
DecompressBlockDXT1Internal (blockStorage, |
|
|
image + x + (y * width), width, transparent0, simpleAlpha, complexAlpha, const_alpha); |
|
|
else |
|
|
DecompressBlockDXT1InternalRGB(blockStorage, ((uint8_t*)image) + x*3 + (y*3 * width), width); |
|
|
} |
|
|
|
|
|
/* |
|
|
void DecompressBlockDXT5(): Decompresses one block of a DXT5 texture and stores the resulting pixels at the appropriate offset in 'image'. |
|
|
|
|
|
uint32_t x: x-coordinate of the first pixel in the block. |
|
|
uint32_t y: y-coordinate of the first pixel in the block. |
|
|
uint32_t width: width of the texture being decompressed. |
|
|
const uint8_t *blockStorage: pointer to the block to decompress. |
|
|
uint32_t *image: pointer to image where the decompressed pixel data should be stored. |
|
|
*/ |
|
|
void DecompressBlockDXT5(uint32_t x, uint32_t y, uint32_t width, |
|
|
const uint8_t* blockStorage, |
|
|
int transparent0, int* simpleAlpha, int *complexAlpha, |
|
|
uint32_t* image) |
|
|
{ |
|
|
uint8_t alpha0, alpha1; |
|
|
const uint8_t* bits; |
|
|
uint32_t alphaCode1; |
|
|
uint16_t alphaCode2; |
|
|
|
|
|
uint16_t color0, color1; |
|
|
uint8_t r0, g0, b0, r1, g1, b1; |
|
|
|
|
|
int i, j; |
|
|
|
|
|
uint32_t temp, code; |
|
|
|
|
|
alpha0 = *(blockStorage); |
|
|
alpha1 = *(blockStorage + 1); |
|
|
|
|
|
bits = blockStorage + 2; |
|
|
alphaCode1 = bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24); |
|
|
alphaCode2 = bits[0] | (bits[1] << 8); |
|
|
|
|
|
color0 = *(const uint16_t*)(blockStorage + 8); |
|
|
color1 = *(const uint16_t*)(blockStorage + 10); |
|
|
|
|
|
temp = (color0 >> 11) * 255 + 16; |
|
|
r0 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color0 & 0x07E0) >> 5) * 255 + 32; |
|
|
g0 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color0 & 0x001F) * 255 + 16; |
|
|
b0 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
temp = (color1 >> 11) * 255 + 16; |
|
|
r1 = (uint8_t)((temp/32 + temp)/32); |
|
|
temp = ((color1 & 0x07E0) >> 5) * 255 + 32; |
|
|
g1 = (uint8_t)((temp/64 + temp)/64); |
|
|
temp = (color1 & 0x001F) * 255 + 16; |
|
|
b1 = (uint8_t)((temp/32 + temp)/32); |
|
|
|
|
|
code = *(const uint32_t*)(blockStorage + 12); |
|
|
|
|
|
for (j = 0; j < 4; j++) { |
|
|
for (i = 0; i < 4; i++) { |
|
|
uint8_t finalAlpha; |
|
|
int alphaCode, alphaCodeIndex; |
|
|
uint8_t colorCode; |
|
|
uint32_t finalColor; |
|
|
|
|
|
alphaCodeIndex = 3*(4*j+i); |
|
|
if (alphaCodeIndex <= 12) { |
|
|
alphaCode = (alphaCode2 >> alphaCodeIndex) & 0x07; |
|
|
} else if (alphaCodeIndex == 15) { |
|
|
alphaCode = (alphaCode2 >> 15) | ((alphaCode1 << 1) & 0x06); |
|
|
} else /* alphaCodeIndex >= 18 && alphaCodeIndex <= 45 */ { |
|
|
alphaCode = (alphaCode1 >> (alphaCodeIndex - 16)) & 0x07; |
|
|
} |
|
|
|
|
|
if (alphaCode == 0) { |
|
|
finalAlpha = alpha0; |
|
|
} else if (alphaCode == 1) { |
|
|
finalAlpha = alpha1; |
|
|
} else { |
|
|
if (alpha0 > alpha1) { |
|
|
finalAlpha = (uint8_t)(((8-alphaCode)*alpha0 + (alphaCode-1)*alpha1)/7); |
|
|
} else { |
|
|
if (alphaCode == 6) { |
|
|
finalAlpha = 0; |
|
|
} else if (alphaCode == 7) { |
|
|
finalAlpha = 255; |
|
|
} else { |
|
|
finalAlpha = (uint8_t)(((6-alphaCode)*alpha0 + (alphaCode-1)*alpha1)/5); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
colorCode = (code >> 2*(4*j+i)) & 0x03; |
|
|
finalColor = 0; |
|
|
|
|
|
switch (colorCode) { |
|
|
case 0: |
|
|
finalColor = PackRGBA(r0, g0, b0, finalAlpha); |
|
|
break; |
|
|
case 1: |
|
|
finalColor = PackRGBA(r1, g1, b1, finalAlpha); |
|
|
break; |
|
|
case 2: |
|
|
finalColor = PackRGBA((2*r0+r1)/3, (2*g0+g1)/3, (2*b0+b1)/3, finalAlpha); |
|
|
break; |
|
|
case 3: |
|
|
finalColor = PackRGBA((r0+2*r1)/3, (g0+2*g1)/3, (b0+2*b1)/3, finalAlpha); |
|
|
break; |
|
|
} |
|
|
|
|
|
if(finalAlpha==0) *simpleAlpha = 1; |
|
|
else if(finalAlpha<0xff) *complexAlpha = 1; |
|
|
|
|
|
image [i + x + (width* (y+j))] = finalColor; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
void DecompressBlockDXT3(): Decompresses one block of a DXT3 texture and stores the resulting pixels at the appropriate offset in 'image'. |
|
|
|
|
|
uint32_t x: x-coordinate of the first pixel in the block. |
|
|
uint32_t y: y-coordinate of the first pixel in the block. |
|
|
uint32_t height: height of the texture being decompressed. |
|
|
const uint8_t *blockStorage: pointer to the block to decompress. |
|
|
uint32_t *image: pointer to image where the decompressed pixel data should be stored. |
|
|
*/ |
|
|
void DecompressBlockDXT3(uint32_t x, uint32_t y, uint32_t width, |
|
|
const uint8_t* blockStorage, |
|
|
int transparent0, int* simpleAlpha, int *complexAlpha, |
|
|
uint32_t* image) |
|
|
{ |
|
|
int i; |
|
|
|
|
|
uint8_t alphaValues [16] = { 0 }; |
|
|
|
|
|
for (i = 0; i < 4; ++i) { |
|
|
const uint16_t* alphaData = (const uint16_t*) (blockStorage); |
|
|
|
|
|
alphaValues [i*4 + 0] = (((*alphaData) >> 0) & 0xF ) * 17; |
|
|
alphaValues [i*4 + 1] = (((*alphaData) >> 4) & 0xF ) * 17; |
|
|
alphaValues [i*4 + 2] = (((*alphaData) >> 8) & 0xF ) * 17; |
|
|
alphaValues [i*4 + 3] = (((*alphaData) >> 12) & 0xF) * 17; |
|
|
|
|
|
blockStorage += 2; |
|
|
} |
|
|
|
|
|
DecompressBlockDXT1Internal (blockStorage, |
|
|
image + x + (y * width), width, transparent0, simpleAlpha, complexAlpha, alphaValues); |
|
|
}
|
|
|
|