| // | |
| // 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 <type_traits> | |
| #include "common/mathutil.h" | |
| #include "image_util/imageformats.h" | |
| namespace angle | |
| { | |
| namespace | |
| { | |
| template <typename T> | |
| 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<const R8G8B8 *>(src)); | |
| case 8: | |
| return ReadColor<>(reinterpret_cast<const R8G8B8A8 *>(src)); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| break; | |
| case 5: | |
| switch (greenBits) | |
| { | |
| case 6: | |
| ASSERT(alphaBits == 0); | |
| return ReadColor<>(reinterpret_cast<const R5G6B5 *>(src)); | |
| case 5: | |
| ASSERT(alphaBits == 1); | |
| return ReadColor<>(reinterpret_cast<const R5G5B5A1 *>(src)); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| break; | |
| case 4: | |
| ASSERT(greenBits == 4 && alphaBits == 4); | |
| return ReadColor<>(reinterpret_cast<const R4G4B4A4 *>(src)); | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| UNREACHABLE(); | |
| return R8G8B8A8{0, 0, 0, 255}; | |
| } | |
| } // namespace | |
| // See LoadPalettedToRGBA8. | |
| void 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) | |
| { | |
| 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<uint8_t>(texels, y, z, inputRowPitch, inputDepthPitch); | |
| R8G8B8A8 *dstRow = | |
| priv::OffsetDataPointer<R8G8B8A8>(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 |