File: Fix-rendering-regression-with-TGA-type-1-files-with-BGRA8.patch

package info (click to toggle)
luanti 5.10.0%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 44,212 kB
  • sloc: cpp: 235,338; java: 4,662; sh: 854; ansic: 450; xml: 335; python: 304; makefile: 39
file content (161 lines) | stat: -rw-r--r-- 6,055 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
From: =?utf-8?q?Lars_M=C3=BCller?=
 <34514239+appgurueu@users.noreply.github.com>
Date: Tue, 19 Nov 2024 13:37:05 +0100
Subject: Fix rendering regression with TGA type 1 files with BGRA8 color
 (#15402)
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

Origin: backport: https://github.com/minetest/minetest/commit/15e8f9e6a06c3ad87bae3ffaf4ec58f551612ff6
Forwarded: not-needed
Applied-Upstream: 5.11.0

TGA uses BGR(A)8, stored in memory in that order. Irrlicht typically expects 0xAARRGGBB, which depends on endianness.
(This means that on little endian, no [B][G][R][A] -> 0xAARRGGBB conversion needs to be done, but Irrlicht was swapping the bytes.)

This makes both conversion functions consistently convert from [B][G][R]([A]) to 0xAARRGGBB (SColor), documents them properly and moves them to CImageLoaderTGA.cpp
so no poor soul shall be fooled by them in the near future.

---------

Co-authored-by: Ælla Chiana Moskopp <erle@dieweltistgarnichtso.net>
---
 irr/src/CColorConverter.cpp | 38 +++++++++-----------------------------
 irr/src/CColorConverter.h   |  2 --
 irr/src/CImage.cpp          |  2 ++
 irr/src/CImageLoaderTGA.cpp | 23 +++++++++++++++++++++--
 4 files changed, 32 insertions(+), 33 deletions(-)

diff --git a/irr/src/CColorConverter.cpp b/irr/src/CColorConverter.cpp
index 96b22c5..d3a5cf6 100644
--- a/irr/src/CColorConverter.cpp
+++ b/irr/src/CColorConverter.cpp
@@ -7,6 +7,15 @@
 #include "os.h"
 #include "irrString.h"
 
+// Warning: The naming of Irrlicht color formats
+// is not consistent regarding actual component order in memory.
+// E.g. in CImage, ECF_R8G8B8 is handled per-byte and stored as [R][G][B] in memory
+// while ECF_A8R8G8B8 is handled as an u32 0xAARRGGBB so [B][G][R][A] (little endian) in memory.
+// The conversions suffer from the same inconsistencies, e.g.
+// convert_R8G8B8toA8R8G8B8 converts [R][G][B] into 0xFFRRGGBB = [B][G][R][FF] (little endian);
+// convert_A1R5G5B5toR8G8B8 converts 0bARRRRRGGGGGBBBBB into [R][G][B].
+// This also means many conversions may be broken on big endian.
+
 namespace irr
 {
 namespace video
@@ -480,19 +489,6 @@ void CColorConverter::convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP)
 	}
 }
 
-void CColorConverter::convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP)
-{
-	u8 *sB = (u8 *)sP;
-	u32 *dB = (u32 *)dP;
-
-	for (s32 x = 0; x < sN; ++x) {
-		*dB = 0xff000000 | (sB[2] << 16) | (sB[1] << 8) | sB[0];
-
-		sB += 3;
-		++dB;
-	}
-}
-
 void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP)
 {
 	const u32 *sB = (const u32 *)sP;
@@ -515,22 +511,6 @@ void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *d
 	}
 }
 
-void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP)
-{
-	u8 *sB = (u8 *)sP;
-	u8 *dB = (u8 *)dP;
-
-	for (s32 x = 0; x < sN; ++x) {
-		dB[0] = sB[3];
-		dB[1] = sB[2];
-		dB[2] = sB[1];
-		dB[3] = sB[0];
-
-		sB += 4;
-		dB += 4;
-	}
-}
-
 void CColorConverter::convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP)
 {
 	u8 *sB = (u8 *)sP;
diff --git a/irr/src/CColorConverter.h b/irr/src/CColorConverter.h
index 7f16282..0bffa26 100644
--- a/irr/src/CColorConverter.h
+++ b/irr/src/CColorConverter.h
@@ -74,8 +74,6 @@ class CColorConverter
 	static void convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP);
 	static void convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP);
 	static void convert_R8G8B8toR5G6B5(const void *sP, s32 sN, void *dP);
-	static void convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP);
-	static void convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP);
 	static void convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP);
 	static void convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *dP);
 
diff --git a/irr/src/CImage.cpp b/irr/src/CImage.cpp
index 2095901..0c6d705 100644
--- a/irr/src/CImage.cpp
+++ b/irr/src/CImage.cpp
@@ -95,6 +95,8 @@ SColor CImage::getPixel(u32 x, u32 y) const
 	case ECF_A8R8G8B8:
 		return ((u32 *)Data)[y * Size.Width + x];
 	case ECF_R8G8B8: {
+		// FIXME this interprets the memory as [R][G][B], whereas SColor is stored as
+		// 0xAARRGGBB, meaning it is lies in memory as [B][G][R][A] on a little endian machine.
 		u8 *p = Data + (y * 3) * Size.Width + (x * 3);
 		return SColor(255, p[0], p[1], p[2]);
 	}
diff --git a/irr/src/CImageLoaderTGA.cpp b/irr/src/CImageLoaderTGA.cpp
index 274b155..75b0b56 100644
--- a/irr/src/CImageLoaderTGA.cpp
+++ b/irr/src/CImageLoaderTGA.cpp
@@ -93,6 +93,25 @@ bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile *file) const
 	return (!strcmp(footer.Signature, "TRUEVISION-XFILE.")); // very old tgas are refused.
 }
 
+/// Converts *byte order* BGR to *endianness order* ARGB (SColor "=" u32)
+static void convert_BGR8_to_SColor(const u8 *src, u32 n, u32 *dst)
+{
+	for (u32 i = 0; i < n; ++i) {
+		const u8 *bgr = &src[3 * i];
+		dst[i] = 0xff000000 | (bgr[2] << 16) | (bgr[1] << 8) | bgr[0];
+	}
+}
+
+/// Converts *byte order* BGRA to *endianness order* ARGB (SColor "=" u32)
+/// Note: This just copies from src to dst on little endian.
+static void convert_BGRA8_to_SColor(const u8 *src, u32 n, u32 *dst)
+{
+	for (u32 i = 0; i < n; ++i) {
+		const u8 *bgra = &src[4 * i];
+		dst[i] = (bgra[3] << 24) | (bgra[2] << 16) | (bgra[1] << 8) | bgra[0];
+	}
+}
+
 //! creates a surface from the file
 IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const
 {
@@ -139,10 +158,10 @@ IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const
 			CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette);
 			break;
 		case 24:
-			CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
+			convert_BGR8_to_SColor(colorMap, header.ColorMapLength, palette);
 			break;
 		case 32:
-			CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
+			convert_BGRA8_to_SColor(colorMap, header.ColorMapLength, palette);
 			break;
 		}
 		delete[] colorMap;