diff --git a/Globals.cpp b/Globals.cpp index 284ba8ef..912df735 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -626,6 +626,10 @@ global_settings::ConfigParse(cParser &Parser) { Parser.getTokens( 1 ); Parser >> loading_log; } + else if (token == "ddsupperorigin") { + Parser.getTokens( 1 ); + Parser >> dds_upper_origin; + } } while ((token != "") && (token != "endconfig")); //(!Parser->EndOfFile) // na koniec trochę zależności if (!bLoadTraction) // wczytywanie drutów i słupów diff --git a/Globals.h b/Globals.h index 4003b3b0..24077958 100644 --- a/Globals.h +++ b/Globals.h @@ -167,6 +167,7 @@ struct global_settings { motiontelemetry::conf_t motiontelemetry_conf; std::string screenshot_dir; bool loading_log = true; + bool dds_upper_origin = false; // methods void LoadIniFile( std::string asFileName ); diff --git a/Texture.cpp b/Texture.cpp index 23441d84..8cf8f8ad 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -23,7 +23,7 @@ http://mozilla.org/MPL/2.0/. #include "Logs.h" #include "sn_utils.h" #include "utilities.h" - +#include "flip-s3tc.h" #include #define EU07_DEFERRED_TEXTURE_UPLOAD @@ -319,26 +319,7 @@ opengl_texture::load_DDS() { } size_t datasize = filesize - offset; -/* - // this approach loads only the first mipmap and relies on graphics card to fill the rest - data_mapcount = 1; - int datasize = ( ( data_width + 3 ) / 4 ) * ( ( data_height + 3 ) / 4 ) * blockSize; -*/ -/* - // calculate size of accepted data - // NOTE: this is a fallback, as we should be able to just move the file caret by calculated offset and read the rest - int datasize = 0; - int mapcount = data_mapcount, - width = data_width, - height = data_height; - while( mapcount ) { - datasize += ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; - width = std::max( width / 2, 4 ); - height = std::max( height / 2, 4 ); - --mapcount; - } -*/ if( datasize == 0 ) { // catch malformed .dds files WriteLog( "Bad texture: file \"" + name + "\" is malformed and holds no texture data.", logtype::texture ); @@ -347,6 +328,7 @@ opengl_texture::load_DDS() { } // reserve space and load texture data data.resize( datasize ); + if( offset != 0 ) { // skip data for mipmaps we don't need file.seekg( offset, std::ios_base::cur ); @@ -355,8 +337,29 @@ opengl_texture::load_DDS() { file.read((char *)&data[0], datasize); filesize -= datasize; - // we're storing texture data internally with bottom-left origin - // ...and DDS stores it with top-left origin! bug here, needs flip! + // we're storing texture data internally with bottom-left origin, + // while DDS stores it with top-left origin. we need to flip it. + if (Global.dds_upper_origin) + { + char *mipmap = (char*)&data[0]; + int mapcount = data_mapcount, + width = data_width, + height = data_height; + while (mapcount) + { + if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) + flip_s3tc::flip_dxt1_image(mipmap, width, height); + else if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT3) + flip_s3tc::flip_dxt23_image(mipmap, width, height); + else if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT5) + flip_s3tc::flip_dxt45_image(mipmap, width, height); + + mipmap += ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ) * blockSize; + width = std::max( width / 2, 4 ); + height = std::max( height / 2, 4 ); + --mapcount; + } + } data_components = ( ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1 ? diff --git a/flip-s3tc.h b/flip-s3tc.h new file mode 100644 index 00000000..a529add4 --- /dev/null +++ b/flip-s3tc.h @@ -0,0 +1,207 @@ +// https://github.com/inequation/flip-s3tc +// Leszek Godlewski places this file in the public domain. + +#pragma once + +#include + +#ifdef __cplusplus +namespace flip_s3tc +{ +#endif + +#pragma pack(push, 1) + +struct dxt1_block +{ + uint16_t c0, c1; + uint8_t dcba, + hgfe, + lkji, + ponm; +}; + +struct dxt23_block +{ + uint16_t adacabaa, + ahagafae, + alakajai, + apaoanam; + uint16_t c0, c1; + uint8_t dcba, + hgfe, + lkji, + ponm; +}; + +struct dxt45_block +{ + uint8_t a0, a1; + struct + { + uint8_t alpha[3]; + } ahagafaeadacabaa, + apaoanamalakajai; + uint16_t c0, c1; + uint8_t dcba, + hgfe, + lkji, + ponm; +}; + +#pragma pack(pop) + +/** Performs an Y-flip of the given DXT1 block in place. */ +void flip_dxt1_block(struct dxt1_block *block) +{ + uint8_t temp; + + temp = block->dcba; + block->dcba = block->ponm; + block->ponm = temp; + temp = block->hgfe; + block->hgfe = block->lkji; + block->lkji = temp; +} + +/** Performs an Y-flip of the given DXT2/DXT3 block in place. */ +void flip_dxt23_block(struct dxt23_block *block) +{ + uint8_t temp8; + uint16_t temp16; + + temp16 = block->adacabaa; + block->adacabaa = block->apaoanam; + block->apaoanam = temp16; + temp16 = block->ahagafae; + block->ahagafae = block->alakajai; + block->alakajai = temp16; + + temp8 = block->dcba; + block->dcba = block->ponm; + block->ponm = temp8; + temp8 = block->hgfe; + block->hgfe = block->lkji; + block->lkji = temp8; +} + +/** Performs an Y-flip of the given DXT4/DXT5 block in place. */ +void flip_dxt45_block(struct dxt45_block *block) +{ + uint8_t temp8; + uint32_t temp32; + uint32_t *as_int[2]; + + as_int[0] = (uint32_t *)block->ahagafaeadacabaa.alpha; + as_int[1] = (uint32_t *)block->apaoanamalakajai.alpha; + // swap adacabaa with apaoanam + temp32 = *as_int[0] & ((1 << 12) - 1); + *as_int[0] &= ~((1 << 12) - 1); + *as_int[0] |= (*as_int[1] & (((1 << 12) - 1) << 12)) >> 12; + *as_int[1] &= ~(((1 << 12) - 1) << 12); + *as_int[1] |= temp32 << 12; + // swap ahagafae with alakajai + temp32 = *as_int[0] & (((1 << 12) - 1) << 12); + *as_int[0] &= ~(((1 << 12) - 1) << 12); + *as_int[0] |= (*as_int[1] & ((1 << 12) - 1)) << 12; + *as_int[1] &= ~((1 << 12) - 1); + *as_int[1] |= temp32 >> 12; + + temp8 = block->dcba; + block->dcba = block->ponm; + block->ponm = temp8; + temp8 = block->hgfe; + block->hgfe = block->lkji; + block->lkji = temp8; +} + +/** + * Performs an Y-flip on the given DXT1 image in place. + * @param data buffer with image data (S3TC blocks) + * @param width image width in pixels + * @param height image height in pixels + */ +void flip_dxt1_image(void *data, int width, int height) +{ + int x, y; + struct dxt1_block temp1, temp2; + struct dxt1_block *blocks = (struct dxt1_block *)data; + + width = (width + 3) / 4; + height = (height + 3) / 4; + + for (y = 0; y < height / 2; ++y) + { + for (x = 0; x < width; ++x) + { + temp1 = blocks[y * width + x]; + temp2 = blocks[(height - y - 1) * width + x]; + flip_dxt1_block(&temp1); + flip_dxt1_block(&temp2); + blocks[(height - y - 1) * width + x] = temp1; + blocks[y * width + x] = temp2; + } + } +} + +/** + * Performs an Y-flip on the given DXT2/DXT3 image in place. + * @param data buffer with image data (S3TC blocks) + * @param width image width in pixels + * @param height image height in pixels + */ +void flip_dxt23_image(void *data, int width, int height) +{ + int x, y; + struct dxt23_block temp1, temp2; + struct dxt23_block *blocks = (struct dxt23_block *)data; + + width = (width + 3) / 4; + height = (height + 3) / 4; + + for (y = 0; y < height / 2; ++y) + { + for (x = 0; x < width; ++x) + { + temp1 = blocks[y * width + x]; + temp2 = blocks[(height - y - 1) * width + x]; + flip_dxt23_block(&temp1); + flip_dxt23_block(&temp2); + blocks[(height - y - 1) * width + x] = temp1; + blocks[y * width + x] = temp2; + } + } +} + +/** + * Performs an Y-flip on the given DXT1 image in place. + * @param data buffer with image data (S3TC blocks) + * @param width image width in pixels + * @param height image height in pixels + */ +void flip_dxt45_image(void *data, int width, int height) +{ + int x, y; + struct dxt45_block temp1, temp2; + struct dxt45_block *blocks = (struct dxt45_block *)data; + + width = (width + 3) / 4; + height = (height + 3) / 4; + + for (y = 0; y < height / 2; ++y) + { + for (x = 0; x < width; ++x) + { + temp1 = blocks[y * width + x]; + temp2 = blocks[(height - y - 1) * width + x]; + flip_dxt45_block(&temp1); + flip_dxt45_block(&temp2); + blocks[(height - y - 1) * width + x] = temp1; + blocks[y * width + x] = temp2; + } + } +} + +#if __cplusplus +} // namespace flip_s3tc +#endif