// // Copyright 2022 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // loadimage_paletted.cpp: Decodes GL_PALETTE_* textures. #include "image_util/loadimage.h" #include #include "common/mathutil.h" #include "image_util/imageformats.h" namespace angle { namespace { template R8G8B8A8 ReadColor(const T *src) { gl::ColorF tmp; T::readColor(&tmp, src); R8G8B8A8 rgba; R8G8B8A8::writeColor(&rgba, &tmp); return rgba; } size_t DecodeIndexIntoPalette(const uint8_t *row, size_t i, uint32_t indexBits) { switch (indexBits) { case 4: { // From OES_compressed_paletted_texture, section Additions to // Chapter 3 of the OpenGL 1.3 Specification (Rasterization): // // Texel Data Formats for compressed paletted textures // // PALETTE4_xxx: // // 7 6 5 4 3 2 1 0 // --------------- // | 1st | 2nd | // | texel | texel | // --------------- bool even = i % 2 == 0; return (row[i / 2] >> (even ? 4 : 0)) & 0x0f; } case 8: return row[i]; default: UNREACHABLE(); return 0; } } R8G8B8A8 DecodeColor(const uint8_t *src, uint32_t redBlueBits, uint32_t greenBits, uint32_t alphaBits) { switch (redBlueBits) { case 8: ASSERT(greenBits == 8); switch (alphaBits) { case 0: return ReadColor<>(reinterpret_cast(src)); case 8: return ReadColor<>(reinterpret_cast(src)); default: UNREACHABLE(); break; } break; case 5: switch (greenBits) { case 6: ASSERT(alphaBits == 0); return ReadColor<>(reinterpret_cast(src)); case 5: ASSERT(alphaBits == 1); return ReadColor<>(reinterpret_cast(src)); default: UNREACHABLE(); break; } break; case 4: ASSERT(greenBits == 4 && alphaBits == 4); return ReadColor<>(reinterpret_cast(src)); default: UNREACHABLE(); break; } UNREACHABLE(); return R8G8B8A8{0, 0, 0, 255}; } } // namespace // See LoadPalettedToRGBA8. void LoadPalettedToRGBA8Impl(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) { size_t colorBytes = (redBlueBits + greenBits + redBlueBits + alphaBits) / 8; size_t paletteSize = 1 << indexBits; size_t paletteBytes = paletteSize * colorBytes; const uint8_t *palette = input; const uint8_t *texels = input + paletteBytes; // + TODO(http://anglebug.com/7688): mip levels for (size_t z = 0; z < depth; z++) { for (size_t y = 0; y < height; y++) { const uint8_t *srcRow = priv::OffsetDataPointer(texels, y, z, inputRowPitch, inputDepthPitch); R8G8B8A8 *dstRow = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); for (size_t x = 0; x < width; x++) { size_t indexIntoPalette = DecodeIndexIntoPalette(srcRow, x, indexBits); dstRow[x] = DecodeColor(palette + indexIntoPalette * colorBytes, redBlueBits, greenBits, alphaBits); } } } } } // namespace angle