diff --git a/src/w3d/renderer/ddsfile.cpp b/src/w3d/renderer/ddsfile.cpp index 7a7390ec5..f557af01a 100644 --- a/src/w3d/renderer/ddsfile.cpp +++ b/src/w3d/renderer/ddsfile.cpp @@ -19,6 +19,11 @@ #include #include +// losely based on http://www.nvidia.com/view.asp?IO=dxtc_decompression_code +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/hh/dx8_c/graphics_using_0j03.asp +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dx8_c/directx_cpp/Graphics/ProgrammersGuide/Appendix/DDSFileFormat/ovwDDSFileFormat.asp + + using rts::FourCC; using std::memcpy; using std::strlen; @@ -382,7 +387,7 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, // Gen and ZH only handle DXT1 and DXT5 switch (m_format) { case WW3D_FORMAT_DXT1: { - int offset = (src_x / 4) + (src_y / 4) * (Get_Width(level) / 4); + int offset = (src_x / 4) * 8 + ((src_y / 4) * (Get_Width(level) / 4)); unsigned dst_pixel = 0; uint8_t *block_mem = &Get_Memory_Pointer(level)[8 * offset]; uint32_t color_a = Decode_Packed_565(block_mem); @@ -405,29 +410,26 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, dst_ptr += dst_pitch; for (int i = 0; i < 4; ++i) { - uint32_t final_color = 0; switch (block_mem[j + 4] & 3) { case 0: - final_color = color_a; + dst_pixel = color_a; break; case 1: - final_color = color_b; + dst_pixel = color_b; break; case 2: - final_color = ((85 * (color_b & 0xFF00) + 170 * (color_a & 0xFF00)) >> 8) & 0xFF00 - | ((85 * (color_b & 0xFF00FF) + 170 * (color_a & 0xFF00FF)) >> 8) & 0xFF00FF; + dst_pixel = Build_Pixel(color_b, color_a, 85); break; case 3: - final_color = ((85 * (color_a & 0xFF00) + 170 * (color_b & 0xFF00)) >> 8) & 0xFF00 - | ((85 * (color_a & 0xFF00FF) + 170 * (color_b & 0xFF00FF)) >> 8) & 0xFF00FF; + dst_pixel = Build_Pixel(color_a, color_b, 85); break; default: break; } - final_color |= 0xFF000000; - Color_To_Format(putp, final_color, dst_format); + dst_pixel |= 0xFF000000; + Color_To_Format(putp, dst_pixel, dst_format); putp += dst_bpp; } } @@ -447,29 +449,26 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, dst_ptr += dst_pitch; for (int i = 0; i < 4; ++i) { - uint32_t final_color = 0; switch (block_mem[j + 4] & 3) { case 0: - final_color = color_a; + dst_pixel = color_a; break; case 1: - final_color = color_b; + dst_pixel = color_b; break; case 2: - final_color = - ((127 * (color_a & 0xFF00) + ((uint16_t)(color_b & 0xFF00) << 7)) >> 8) & 0xFF00 - | ((((color_b & 0xFF00FF) << 7) + 0x7F * (color_a & 0xFF00FF)) >> 8) & 0xFF00FF; + dst_pixel = Build_Pixel(color_b, color_a, 128); break; case 3: - final_color = 0; + dst_pixel = 0; break; default: break; } - final_color |= 0xFF000000; - Color_To_Format(putp, final_color, dst_format); + dst_pixel |= 0xFF000000; + Color_To_Format(putp, dst_pixel, dst_format); putp += dst_bpp; } } @@ -479,7 +478,7 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, } return has_alpha; case WW3D_FORMAT_DXT5: { - int offset = (src_x / 4) + (src_y / 4) * (Get_Width(level) / 4); + int offset = (src_x / 4) * 16 + ((src_y / 4) * (Get_Width(level) / 4)); unsigned dst_pixel = 0; uint8_t *block_mem = &Get_Memory_Pointer(level)[16 * offset]; @@ -490,20 +489,23 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, alphas[0] = alpha0; alphas[1] = alpha1; + // 8-alpha or 6-alpha block? if (alpha0 > alpha1) { - alphas[2] = (alpha1 + 6 * alpha0 + 3) / 7; - alphas[3] = (5 * alpha0 + 2 * alpha1 + 3) / 7; - alphas[4] = (3 * alpha1 + 3 + 4 * alpha0) / 7; - alphas[5] = (3 * alpha0 + 3 + 4 * alpha1) / 7; - alphas[6] = (5 * alpha1 + 2 * alpha0 + 3) / 7; - alphas[7] = (alpha0 + 6 * alpha1 + 3) / 7; + alphas[2] = (6 * alpha1 + alpha0 + 3) / 7; // Bit code 010 + alphas[3] = (5 * alpha0 + 2 * alpha1 + 3) / 7; // Bit code 011 + alphas[4] = (3 * alpha1 + 4 * alpha0 + 3) / 7; // Bit code 100 + alphas[5] = (3 * alpha0 + 4 * alpha1 + 3) / 7; // Bit code 101 + alphas[6] = (5 * alpha1 + 2 * alpha0 + 3) / 7; // Bit code 110 + alphas[7] = (alpha0 + 6 * alpha1 + 3) / 7; // Bit code 111 } else { - alphas[2] = (alpha1 + 4 * alpha0 + 2) / 5; - alphas[6] = 0; - alphas[7] = 255; - alphas[3] = (3 * alpha0 + 2 * alpha1 + 2) / 5; - alphas[4] = (3 * alpha1 + 2 * alpha0 + 2) / 5; - alphas[5] = (alpha0 + 4 * alpha1 + 2) / 5; + // 6-alpha block: derive the other alphas. + // 000 = alpha_0, 001 = alpha_1, others are interpolated + alphas[2] = (4 * alpha9 + alpha1 + 2) / 5; // Bit code 010 + alphas[3] = (3 * alpha0 + 2 * alpha1 + 2) / 5; // Bit code 011 + alphas[4] = (3 * alpha1 + 2 * alpha0 + 2) / 5; // Bit code 100 + alphas[5] = (alpha0 + 4 * alpha1 + 2) / 5; // Bit code 101 + alphas[6] = 0; // Bit code 110 + alphas[7] = 255; // Bit code 111 } uint32_t color_a = Decode_Packed_565(block_mem + 8); @@ -533,27 +535,24 @@ bool DDSFileClass::Get_4x4_Block(uint8_t *dst_ptr, for (int i = 0; i < 4; i++) { unsigned alpha = alphas[alpha_indices[j * 4 + i]]; has_alpha = alpha < 255; - uint32_t final_color = 0; switch (((block_mem[j + 12]) >> (2 * i)) & 3) { case 0: - final_color = color_a | (alpha << 24); + dst_pixel = color_a | (alpha << 24); break; case 1: - final_color = color_b | (alpha << 24); + dst_pixel = color_b | (alpha << 24); break; case 2: - final_color = ((85 * (color_b & 0xFF00) + 170 * (color_a & 0xFF00)) >> 8) & 0xFF00 - | ((85 * (color_b & 0xFF00FF) + 170 * (color_a & 0xFF00FF)) >> 8) & 0xFF00FF; + dst_pixel = Build_Pixel(color_b, color_a, 85); break; case 3: - final_color = ((85 * (color_a & 0xFF00) + 170 * (color_b & 0xFF00)) >> 8) & 0xFF00 - | ((85 * (color_a & 0xFF00FF) + 170 * (color_b & 0xFF00FF)) >> 8) & 0xFF00FF; + dst_pixel = Build_Pixel(color_b, color_a, 85); break; } - final_color |= alpha; - Color_To_Format(putp, final_color, dst_format); + dst_pixel |= alpha; + Color_To_Format(putp, dst_pixel, dst_format); putp += dst_bpp; } } diff --git a/src/w3d/renderer/ddsfile.h b/src/w3d/renderer/ddsfile.h index 243c67beb..dd8cb7dd0 100644 --- a/src/w3d/renderer/ddsfile.h +++ b/src/w3d/renderer/ddsfile.h @@ -151,6 +151,7 @@ class DDSFileClass static unsigned Calculate_S3TC_Surface_Size(unsigned width, unsigned height, WW3DFormat format); static uint32_t Decode_Packed_565(uint8_t *packed); static uint32_t Decode_Line_Code(uint8_t *packed); + static uint32_t Build_Pixel(uint32_t color_a, uint32_t color_b, uint32_t s1); private: unsigned m_width; @@ -178,6 +179,16 @@ inline uint32_t DDSFileClass::Decode_Packed_565(uint8_t *packed) return ((value & 0x1F) | ((value & 0x7E0) | ((value & 0xF800) << 3) << 2)) << 3; } +static uint32_t DDSFileClass::Build_Pixel(uint32_t color_a, uint32_t color_b, uint32_t s1) +{ + uint32_t s2 = 0xFF - s; + const uint32_t G_MASK = 0x0000FF00; + const uint32_t R_B_MASK = 0x00FF00FF; + + return ((s2 * (color_a & G_MASK)) + (s1 * (color_b & G_MASK)) >> 8) & G_MASK + | ((s2 * (color_a & R_B_MASK)) + (s1 * (color_b & R_B_MASK)) >> 8) & R_B_MASK; +} + inline uint32_t DDSFileClass::Decode_Line_Code(uint8_t *packed) { return uint32_t(packed[0]) | (uint32_t(packed[1]) << 8) | (uint32_t(packed[2]) << 16) | (uint32_t(packed[3]) << 24);