From a276c16fb5e70689f5048ba1fad63a2a9f6c7625 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Thu, 11 Jul 2024 04:42:46 +0200 Subject: [PATCH] stb_image: support horizontally flipped TGA images The TGA format is a bottom-left format by default: the first byte of the first column is expected to be displayed at the bottom-left of the screen, this behavior is inherited from devices painting the screen from the bottom left to the top right. The TGA format provides two bits in the image descriptor byte to paint the data from other sides. The 4th bit tells the device to paint the screen from right-to left and the 5th bit tells the device to paint the screen from top to bottom. So basically: - 00: from bottom-left to top-right - 01: from top-left to bottom-right - 10: from bottom-right to top-left - 11: from top-right to bottom-left Previously stb_image only read the 5th bit and then only supported the loading of vertically flipped images, stb_image was ignoring the 4th bit coding the horizontal flip. Now both flipping directions are supported for both raw and RLE storage. --- crnlib/stb_image.h | 50 ++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/crnlib/stb_image.h b/crnlib/stb_image.h index 9eedabed..de69116e 100644 --- a/crnlib/stb_image.h +++ b/crnlib/stb_image.h @@ -5884,8 +5884,8 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req int tga_height = stbi__get16le(s); int tga_bits_per_pixel = stbi__get8(s); int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + int tga_descriptor = stbi__get8(s); + // int tga_alpha_bits = tga_descriptor & 15; // the 3 lowest bits - unused (useless?) // image data unsigned char *tga_data; unsigned char *tga_palette = NULL; @@ -5907,7 +5907,8 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req tga_image_type -= 8; tga_is_RLE = 1; } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); + int tga_x_inverted = ((tga_descriptor >> 4) & 1); + int tga_y_inverted = 1 - ((tga_descriptor >> 5) & 1); // If I'm paletted, then I'll use the number of bits from the palette if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); @@ -5932,9 +5933,16 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; + int row = tga_y_inverted ? tga_height - i - 1 : i; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); + if (tga_x_inverted) { + for (j = 0; j < tga_width; j++) { + int index = (tga_width - j - 1) * tga_comp; + stbi__getn(s, tga_row + index, tga_comp); + } + } else { + stbi__getn(s, tga_row, tga_width * tga_comp); + } } } else { // do I need to load a palette? @@ -6024,19 +6032,27 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req --RLE_count; } // do I need to invert the image? - if ( tga_inverted ) + if ( tga_x_inverted || tga_y_inverted ) { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; + int col_start = tga_x_inverted ? tga_width - 1 : 0; + int col_iter = tga_x_inverted ? -1 : 1; + int row_start = tga_y_inverted ? tga_height - 1 : 0; + int row_iter = tga_y_inverted ? -1 : 1; + int row = row_start; + for (i = 0; i * 2 < tga_height; i++, row += row_iter) { + int src_row_index = i * tga_width * tga_comp; + int dest_row_index = row * tga_width * tga_comp; + int col = col_start; + for (j = 0; j * 2 < tga_width; j++, col += col_iter) { + int src_col_index = j * tga_comp; + int dest_col_index = col * tga_comp; + for (int k = 0; k < tga_comp; k++) { + stbi_uc *src = tga_data + src_row_index + src_col_index + k; + stbi_uc *dest = tga_data + dest_row_index + dest_col_index + k; + stbi_uc temp = *src; + *src = *dest; + *dest = temp; + } } } }