1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // loadimage_paletted.cpp: Decodes GL_PALETTE_* textures.
8
9 #include "image_util/loadimage.h"
10
11 #include <type_traits>
12 #include "common/mathutil.h"
13
14 #include "image_util/imageformats.h"
15
16 namespace angle
17 {
18
19 namespace
20 {
21
22 template <typename T>
ReadColor(const T * src)23 R8G8B8A8 ReadColor(const T *src)
24 {
25 gl::ColorF tmp;
26 T::readColor(&tmp, src);
27 R8G8B8A8 rgba;
28 R8G8B8A8::writeColor(&rgba, &tmp);
29 return rgba;
30 }
31
DecodeIndexIntoPalette(const uint8_t * row,size_t i,uint32_t indexBits)32 size_t DecodeIndexIntoPalette(const uint8_t *row, size_t i, uint32_t indexBits)
33 {
34 switch (indexBits)
35 {
36 case 4:
37 {
38 // From OES_compressed_paletted_texture, section Additions to
39 // Chapter 3 of the OpenGL 1.3 Specification (Rasterization):
40 //
41 // Texel Data Formats for compressed paletted textures
42 //
43 // PALETTE4_xxx:
44 //
45 // 7 6 5 4 3 2 1 0
46 // ---------------
47 // | 1st | 2nd |
48 // | texel | texel |
49 // ---------------
50
51 bool even = i % 2 == 0;
52 return (row[i / 2] >> (even ? 4 : 0)) & 0x0f;
53 }
54
55 case 8:
56 return row[i];
57
58 default:
59 UNREACHABLE();
60 return 0;
61 }
62 }
63
DecodeColor(const uint8_t * src,uint32_t redBlueBits,uint32_t greenBits,uint32_t alphaBits)64 R8G8B8A8 DecodeColor(const uint8_t *src,
65 uint32_t redBlueBits,
66 uint32_t greenBits,
67 uint32_t alphaBits)
68 {
69 switch (redBlueBits)
70 {
71 case 8:
72 ASSERT(greenBits == 8);
73 switch (alphaBits)
74 {
75 case 0:
76 return ReadColor<>(reinterpret_cast<const R8G8B8 *>(src));
77 case 8:
78 return ReadColor<>(reinterpret_cast<const R8G8B8A8 *>(src));
79 default:
80 UNREACHABLE();
81 break;
82 }
83 break;
84
85 case 5:
86 switch (greenBits)
87 {
88 case 6:
89 ASSERT(alphaBits == 0);
90 return ReadColor<>(reinterpret_cast<const R5G6B5 *>(src));
91 case 5:
92 ASSERT(alphaBits == 1);
93 return ReadColor<>(reinterpret_cast<const R5G5B5A1 *>(src));
94 default:
95 UNREACHABLE();
96 break;
97 }
98 break;
99
100 case 4:
101 ASSERT(greenBits == 4 && alphaBits == 4);
102 return ReadColor<>(reinterpret_cast<const R4G4B4A4 *>(src));
103
104 default:
105 UNREACHABLE();
106 break;
107 }
108
109 UNREACHABLE();
110 return R8G8B8A8{0, 0, 0, 255};
111 }
112
113 } // namespace
114
115 // See LoadPalettedToRGBA8.
LoadPalettedToRGBA8Impl(const ImageLoadContext & context,size_t width,size_t height,size_t depth,uint32_t indexBits,uint32_t redBlueBits,uint32_t greenBits,uint32_t alphaBits,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)116 void LoadPalettedToRGBA8Impl(const ImageLoadContext &context,
117 size_t width,
118 size_t height,
119 size_t depth,
120 uint32_t indexBits,
121 uint32_t redBlueBits,
122 uint32_t greenBits,
123 uint32_t alphaBits,
124 const uint8_t *input,
125 size_t inputRowPitch,
126 size_t inputDepthPitch,
127 uint8_t *output,
128 size_t outputRowPitch,
129 size_t outputDepthPitch)
130 {
131 size_t colorBytes = (redBlueBits + greenBits + redBlueBits + alphaBits) / 8;
132 size_t paletteSize = 1 << indexBits;
133 size_t paletteBytes = paletteSize * colorBytes;
134
135 const uint8_t *palette = input;
136
137 const uint8_t *texels = input + paletteBytes; // + TODO(http://anglebug.com/7688): mip levels
138
139 for (size_t z = 0; z < depth; z++)
140 {
141 for (size_t y = 0; y < height; y++)
142 {
143 const uint8_t *srcRow =
144 priv::OffsetDataPointer<uint8_t>(texels, y, z, inputRowPitch, inputDepthPitch);
145 R8G8B8A8 *dstRow =
146 priv::OffsetDataPointer<R8G8B8A8>(output, y, z, outputRowPitch, outputDepthPitch);
147
148 for (size_t x = 0; x < width; x++)
149 {
150 size_t indexIntoPalette = DecodeIndexIntoPalette(srcRow, x, indexBits);
151
152 dstRow[x] = DecodeColor(palette + indexIntoPalette * colorBytes, redBlueBits,
153 greenBits, alphaBits);
154 }
155 }
156 }
157 }
158
159 } // namespace angle
160