/* * Copyright (c) 2021, Stephan Unverwerth * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include namespace SoftGPU { enum class ImageFormat { RGB565, RGB888, BGR888, RGBA8888, BGRA8888, }; inline static constexpr size_t element_size(ImageFormat format) { switch (format) { case ImageFormat::RGB565: return 2; case ImageFormat::RGB888: case ImageFormat::BGR888: return 3; case ImageFormat::RGBA8888: case ImageFormat::BGRA8888: return 4; default: VERIFY_NOT_REACHED(); } } inline static FloatVector4 unpack_color(void const* ptr, ImageFormat format) { switch (format) { case ImageFormat::RGB888: { auto rgb = reinterpret_cast(ptr); return { rgb[0] / 255.f, rgb[1] / 255.f, rgb[2] / 255.f, 1.0f }; } case ImageFormat::BGR888: { auto bgr = reinterpret_cast(ptr); return { bgr[2] / 255.f, bgr[1] / 255.f, bgr[0] / 255.f, 1.0f }; } case ImageFormat::RGBA8888: { auto rgba = *reinterpret_cast(ptr); return { (rgba & 0xff) / 255.f, ((rgba >> 8) & 0xff) / 255.f, ((rgba >> 16) & 0xff) / 255.f, ((rgba >> 24) & 0xff) / 255.f }; } case ImageFormat::BGRA8888: { auto bgra = *reinterpret_cast(ptr); return { ((bgra >> 16) & 0xff) / 255.f, ((bgra >> 8) & 0xff) / 255.f, (bgra & 0xff) / 255.f, ((bgra >> 24) & 0xff) / 255.f }; } case ImageFormat::RGB565: { auto rgb = *reinterpret_cast(ptr); return { ((rgb >> 11) & 0x1f) / 31.f, ((rgb >> 5) & 0x3f) / 63.f, (rgb & 0x1f) / 31.f, 1.0f }; } default: VERIFY_NOT_REACHED(); } } inline static void pack_color(FloatVector4 const& color, void* ptr, ImageFormat format) { auto r = static_cast(clamp(color.x(), 0.0f, 1.0f) * 255); auto g = static_cast(clamp(color.y(), 0.0f, 1.0f) * 255); auto b = static_cast(clamp(color.z(), 0.0f, 1.0f) * 255); auto a = static_cast(clamp(color.w(), 0.0f, 1.0f) * 255); switch (format) { case ImageFormat::RGB888: reinterpret_cast(ptr)[0] = r; reinterpret_cast(ptr)[1] = g; reinterpret_cast(ptr)[2] = b; return; case ImageFormat::BGR888: reinterpret_cast(ptr)[2] = b; reinterpret_cast(ptr)[1] = g; reinterpret_cast(ptr)[0] = r; return; case ImageFormat::RGBA8888: *reinterpret_cast(ptr) = r | (g << 8) | (b << 16) | (a << 24); return; case ImageFormat::BGRA8888: *reinterpret_cast(ptr) = b | (g << 8) | (r << 16) | (a << 24); return; case ImageFormat::RGB565: *reinterpret_cast(ptr) = (r & 0x1f) | ((g & 0x3f) << 5) | ((b & 0x1f) << 11); return; default: VERIFY_NOT_REACHED(); } } }