// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** emupal.c Palette device. ***************************************************************************/ #include "emu.h" #include "emupal.h" //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** DEFINE_DEVICE_TYPE(PALETTE, palette_device, "palette", "palette") palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, init_delegate &&init, u32 entries, u32 indirect) : palette_device(mconfig, tag, owner, 0U) { set_entries(entries, indirect); m_init = std::move(init); } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, black_t, u32 entries) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_all_black)), entries) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, mono_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_monochrome)), 2) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, mono_inv_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_monochrome_inverted)), 2) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, mono_hi_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_monochrome_highlight)), 3) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, rgb_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_rgb)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, rbg_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_rbg)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, grb_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_grb)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, gbr_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_gbr)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, brg_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_brg)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, bgr_3b_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_3bit_bgr)), 8) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, rgb_555_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_rgb_555)), 32768) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, grb_555_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_grb_555)), 32768) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, bgr_555_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_bgr_555)), 32768) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, rgb_565_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_rgb_565)), 65536) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, bgr_565_t) : palette_device(mconfig, tag, owner, init_delegate(*this, FUNC(palette_device::palette_init_bgr_565)), 65536) { } palette_device::palette_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, PALETTE, tag, owner, clock) , device_palette_interface(mconfig, *this) , m_entries(0) , m_indirect_entries(0) , m_enable_shadows(0) , m_enable_hilights(0) , m_membits(0) , m_membits_supplied(false) , m_endianness() , m_endianness_supplied(false) , m_prom_region(*this, finder_base::DUMMY_TAG) , m_init(*this) , m_raw_to_rgb() { } palette_device &palette_device::set_format(int bytes_per_entry, raw_to_rgb_converter::raw_to_rgb_func func, u32 entries) { set_format(raw_to_rgb_converter(bytes_per_entry, func)); set_entries(entries); return *this; } palette_device &palette_device::set_format(rgb_332_t, u32 entries) { set_format(1, &raw_to_rgb_converter::standard_rgb_decoder<3,3,2, 5,2,0>, entries); return *this; } palette_device &palette_device::set_format(bgr_233_t, u32 entries) { set_format(1, &raw_to_rgb_converter::standard_rgb_decoder<3,3,2, 0,3,6>, entries); return *this; } palette_device &palette_device::set_format(rgb_332_inv_t, u32 entries) { set_format(1, &raw_to_rgb_converter::inverted_rgb_decoder<3,3,2, 5,2,0>, entries); return *this; } palette_device &palette_device::set_format(bgr_233_inv_t, u32 entries) { set_format(1, &raw_to_rgb_converter::inverted_rgb_decoder<3,3,2, 0,3,6>, entries); return *this; } palette_device &palette_device::set_format(xrgb_333_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<3,3,3, 6,3,0>, entries); return *this; } palette_device &palette_device::set_format(xrbg_333_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<3,3,3, 6,0,3>, entries); return *this; } palette_device &palette_device::set_format(xbgr_333_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<3,3,3, 0,3,6>, entries); return *this; } palette_device &palette_device::set_format(xrgb_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 8,4,0>, entries); return *this; } palette_device &palette_device::set_format(xrbg_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 8,0,4>, entries); return *this; } palette_device &palette_device::set_format(xbrg_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 4,0,8>, entries); return *this; } palette_device &palette_device::set_format(xbgr_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 0,4,8>, entries); return *this; } palette_device &palette_device::set_format(rgbx_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 12,8,4>, entries); return *this; } palette_device &palette_device::set_format(gbrx_444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<4,4,4, 4,12,8>, entries); return *this; } palette_device &palette_device::set_format(irgb_4444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_irgb_decoder<4,4,4,4, 12,8,4,0>, entries); return *this; } palette_device &palette_device::set_format(rgbi_4444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_irgb_decoder<4,4,4,4, 0,12,8,4>, entries); return *this; } palette_device &palette_device::set_format(ibgr_4444_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_irgb_decoder<4,4,4,4, 12,0,4,8>, entries); return *this; } palette_device &palette_device::set_format(xrgb_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 10,5,0>, entries); return *this; } palette_device &palette_device::set_format(xgrb_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 5,10,0>, entries); return *this; } palette_device &palette_device::set_format(xgbr_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 0,10,5>, entries); return *this; } palette_device &palette_device::set_format(xbrg_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 5,0,10>, entries); return *this; } palette_device &palette_device::set_format(xbgr_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 0,5,10>, entries); return *this; } palette_device &palette_device::set_format(rgbx_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 11,6,1>, entries); return *this; } palette_device &palette_device::set_format(grbx_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 6,11,1>, entries); return *this; } palette_device &palette_device::set_format(brgx_555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,5,5, 6,1,11>, entries); return *this; } palette_device &palette_device::set_format(xrbg_inv_t, u32 entries) { set_format(2, &raw_to_rgb_converter::inverted_rgb_decoder<5,5,5, 10,0,5>, entries); return *this; } palette_device &palette_device::set_format(irgb_1555_t, u32 entries) { set_format(2, &raw_to_rgb_converter::IRRRRRGGGGGBBBBB_decoder, entries); return *this; } palette_device &palette_device::set_format(rgb_565_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,6,5, 11,5,0>, entries); return *this; } palette_device &palette_device::set_format(bgr_565_t, u32 entries) { set_format(2, &raw_to_rgb_converter::standard_rgb_decoder<5,6,5, 0,5,11>, entries); return *this; } palette_device &palette_device::set_format(xrgb_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 16,8,0>, entries); return *this; } palette_device &palette_device::set_format(xgrb_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 8,16,0>, entries); return *this; } palette_device &palette_device::set_format(xbrg_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 8,0,16>, entries); return *this; } palette_device &palette_device::set_format(xbgr_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 0,8,16>, entries); return *this; } palette_device &palette_device::set_format(rgbx_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 24,16,8>, entries); return *this; } palette_device &palette_device::set_format(grbx_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 16,24,8>, entries); return *this; } palette_device &palette_device::set_format(bgrx_888_t, u32 entries) { set_format(4, &raw_to_rgb_converter::standard_rgb_decoder<8,8,8, 8,16,24>, entries); return *this; } palette_device &palette_device::set_format(rrrrggggbbbbrgbx_t, u32 entries) { set_format(2, &raw_to_rgb_converter::RRRRGGGGBBBBRGBx_decoder, entries); return *this; } palette_device &palette_device::set_format(xrgbrrrrggggbbbb_bit0_t, u32 entries) { set_format(2, &raw_to_rgb_converter::xRGBRRRRGGGGBBBB_bit0_decoder, entries); return *this; } palette_device &palette_device::set_format(xrgbrrrrggggbbbb_bit4_t, u32 entries) { set_format(2, &raw_to_rgb_converter::xRGBRRRRGGGGBBBB_bit4_decoder, entries); return *this; } palette_device &palette_device::set_format(xbgrbbbbggggrrrr_bit0_t, u32 entries) { set_format(2, &raw_to_rgb_converter::xBGRBBBBGGGGRRRR_bit0_decoder, entries); return *this; } //************************************************************************** // GENERIC WRITE HANDLERS //************************************************************************** //------------------------------------------------- // update_for_write - given a write of a given // length to a given byte offset, update all // potentially modified palette entries //------------------------------------------------- inline void palette_device::update_for_write(offs_t byte_offset, int bytes_modified, bool indirect) { assert((m_indirect_entries != 0) == indirect); // determine how many entries were modified int bpe = m_paletteram.bytes_per_entry(); assert(bpe != 0); int count = (bytes_modified + bpe - 1) / bpe; // for each entry modified, fetch the palette data and set the pen color or indirect color offs_t base = byte_offset / bpe; for (int index = 0; index < count; index++) { if (indirect) set_indirect_color(base + index, m_raw_to_rgb(read_entry(base + index))); else set_pen_color(base + index, m_raw_to_rgb(read_entry(base + index))); } } //------------------------------------------------- // write - write a byte to the base paletteram //------------------------------------------------- void palette_device::write8(offs_t offset, u8 data) { m_paletteram.write8(offset, data); update_for_write(offset, 1); } void palette_device::write16(offs_t offset, u16 data, u16 mem_mask) { m_paletteram.write16(offset, data, mem_mask); update_for_write(offset * 2, 2); } void palette_device::write32(offs_t offset, u32 data, u32 mem_mask) { m_paletteram.write32(offset, data, mem_mask); update_for_write(offset * 4, 4); } u8 palette_device::read8(offs_t offset) { return m_paletteram.read8(offset); } u16 palette_device::read16(offs_t offset) { return m_paletteram.read16(offset); } u32 palette_device::read32(offs_t offset) { return m_paletteram.read32(offset); } //------------------------------------------------- // write_ext - write a byte to the extended // paletteram //------------------------------------------------- void palette_device::write8_ext(offs_t offset, u8 data) { m_paletteram_ext.write8(offset, data); update_for_write(offset, 1); } void palette_device::write16_ext(offs_t offset, u16 data, u16 mem_mask) { m_paletteram_ext.write16(offset, data, mem_mask); update_for_write(offset * 2, 2); } u8 palette_device::read8_ext(offs_t offset) { return m_paletteram_ext.read8(offset); } u16 palette_device::read16_ext(offs_t offset) { return m_paletteram_ext.read16(offset); } //------------------------------------------------- // write_indirect - write a byte to the base // paletteram, updating indirect colors //------------------------------------------------- void palette_device::write_indirect(offs_t offset, u8 data) { m_paletteram.write8(offset, data); update_for_write(offset, 1, true); } //------------------------------------------------- // write_ext - write a byte to the extended // paletteram, updating indirect colors //------------------------------------------------- void palette_device::write_indirect_ext(offs_t offset, u8 data) { m_paletteram_ext.write8(offset, data); update_for_write(offset, 1, true); } //************************************************************************** // DEVICE MANAGEMENT //************************************************************************** //------------------------------------------------- // device_start - start up the device //------------------------------------------------- void palette_device::device_start() { // bind the init function m_init.resolve(); // find the memory, if present const memory_share *share = memshare(tag()); if (share != nullptr) { // find the extended (split) memory, if present std::string tag_ext = std::string(tag()).append("_ext"); const memory_share *share_ext = memshare(tag_ext.c_str()); // make sure we have specified a format if (m_raw_to_rgb.bytes_per_entry() <= 0) throw emu_fatalerror("palette_device(%s): Palette has memory share but no format specified", tag()); // determine bytes per entry and configure int bytes_per_entry = m_raw_to_rgb.bytes_per_entry(); if (share_ext == nullptr) m_paletteram.set(*share, bytes_per_entry); else { m_paletteram.set(*share, bytes_per_entry / 2); m_paletteram_ext.set(*share_ext, bytes_per_entry / 2); } // override membits if provided if (m_membits_supplied) { // forcing width only makes sense when narrower than the native bus width if (m_membits >= share->bitwidth()) throw emu_fatalerror("palette_device(%s): Improper use of MCFG_PALETTE_MEMBITS", tag()); m_paletteram.set_membits(m_membits); if (share_ext != nullptr) m_paletteram_ext.set_membits(m_membits); } // override endianness if provided if (m_endianness_supplied) { // forcing endianness only makes sense when the RAM is narrower than the palette format and not split if (share_ext || (m_paletteram.membits() / 8) >= bytes_per_entry) throw emu_fatalerror("palette_device(%s): Improper use of MCFG_PALETTE_ENDIANNESS", tag()); m_paletteram.set_endianness(m_endianness); } } // call the initialization helper if present if (!m_init.isnull()) m_init(*this); } //************************************************************************** // COMMON PALETTE INITIALIZATION //************************************************************************** /*------------------------------------------------- black - completely black palette -------------------------------------------------*/ void palette_device::palette_init_all_black(palette_device &palette) { for (int i = 0; i < palette.entries(); i++) { palette.set_pen_color(i, rgb_t::black()); } } /*------------------------------------------------- monochrome - 2-color black & white -------------------------------------------------*/ void palette_device::palette_init_monochrome(palette_device &palette) { palette.set_pen_color(0, rgb_t::black()); palette.set_pen_color(1, rgb_t::white()); } /*------------------------------------------------- monochrome_inverted - 2-color white & black -------------------------------------------------*/ void palette_device::palette_init_monochrome_inverted(palette_device &palette) { palette.set_pen_color(0, rgb_t::white()); palette.set_pen_color(1, rgb_t::black()); } /*------------------------------------------------- monochrome_highlight - 3-color -------------------------------------------------*/ void palette_device::palette_init_monochrome_highlight(palette_device &palette) { palette.set_pen_color(0, rgb_t::black()); palette.set_pen_color(1, rgb_t(0xc0, 0xc0, 0xc0)); palette.set_pen_color(2, rgb_t::white()); } /*------------------------------------------------- 3bit_rgb - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_rgb(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2))); } /*------------------------------------------------- 3bit_rbg - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_rbg(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 0), pal1bit(i >> 2), pal1bit(i >> 1))); } /*------------------------------------------------- 3bit_brg - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_brg(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 1), pal1bit(i >> 2), pal1bit(i >> 0))); } /*------------------------------------------------- 3bit_grb - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_grb(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 1), pal1bit(i >> 0), pal1bit(i >> 2))); } /*------------------------------------------------- 3bit_gbr - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_gbr(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 2), pal1bit(i >> 0), pal1bit(i >> 1))); } /*------------------------------------------------- 3bit_bgr - 8-color rgb -------------------------------------------------*/ void palette_device::palette_init_3bit_bgr(palette_device &palette) { for (int i = 0; i < 8; i++) palette.set_pen_color(i, rgb_t(pal1bit(i >> 2), pal1bit(i >> 1), pal1bit(i >> 0))); } /*------------------------------------------------- RRRR_GGGG_BBBB - standard 4-4-4 palette, assuming the commonly used resistor values: bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE -- 470 ohm resistor -- RED/GREEN/BLUE -- 1 kohm resistor -- RED/GREEN/BLUE bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE -------------------------------------------------*/ void palette_device::palette_init_rgb_444_proms(palette_device &palette) { if (!m_prom_region.found()) throw emu_fatalerror("Unable to find color PROM region '%s'.", m_prom_region.finder_tag()); const u8 *colors = m_prom_region->base(); for (int i = 0; i < palette.entries(); i++) { int bit0, bit1, bit2, bit3; // red component bit0 = (colors[i] >> 0) & 0x01; bit1 = (colors[i] >> 1) & 0x01; bit2 = (colors[i] >> 2) & 0x01; bit3 = (colors[i] >> 3) & 0x01; int r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3; // green component bit0 = (colors[i + palette.entries()] >> 0) & 0x01; bit1 = (colors[i + palette.entries()] >> 1) & 0x01; bit2 = (colors[i + palette.entries()] >> 2) & 0x01; bit3 = (colors[i + palette.entries()] >> 3) & 0x01; int g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3; // blue component bit0 = (colors[i + 2*palette.entries()] >> 0) & 0x01; bit1 = (colors[i + 2*palette.entries()] >> 1) & 0x01; bit2 = (colors[i + 2*palette.entries()] >> 2) & 0x01; bit3 = (colors[i + 2*palette.entries()] >> 3) & 0x01; int b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3; palette.set_pen_color(i, rgb_t(r,g,b)); } } /*------------------------------------------------- standard 5-5-5 palette for games using a 15-bit color space -------------------------------------------------*/ void palette_device::palette_init_rgb_555(palette_device &palette) { for (int i = 0; i < 0x8000; i++) palette.set_pen_color(i, rgbexpand<5,5,5>(i, 10, 5, 0)); } void palette_device::palette_init_grb_555(palette_device &palette) { for (int i = 0; i < 0x8000; i++) palette.set_pen_color(i, rgbexpand<5,5,5>(i, 5, 10, 0)); } void palette_device::palette_init_bgr_555(palette_device &palette) { for (int i = 0; i < 0x8000; i++) palette.set_pen_color(i, rgbexpand<5,5,5>(i, 0, 5, 10)); } /*------------------------------------------------- standard 5-6-5 palette for games using a 16-bit color space -------------------------------------------------*/ void palette_device::palette_init_rgb_565(palette_device &palette) { for (int i = 0; i < 0x10000; i++) palette.set_pen_color(i, rgbexpand<5,6,5>(i, 11, 5, 0)); } void palette_device::palette_init_bgr_565(palette_device &palette) { for (int i = 0; i < 0x10000; i++) palette.set_pen_color(i, rgbexpand<5,6,5>(i, 0, 5, 11)); } rgb_t raw_to_rgb_converter::IRRRRRGGGGGBBBBB_decoder(u32 raw) { u8 const i = (raw >> 15) & 1; u8 const r = pal6bit(((raw >> 9) & 0x3e) | i); u8 const g = pal6bit(((raw >> 4) & 0x3e) | i); u8 const b = pal6bit(((raw << 1) & 0x3e) | i); return rgb_t(r, g, b); } rgb_t raw_to_rgb_converter::RRRRGGGGBBBBRGBx_decoder(u32 raw) { u8 const r = pal5bit(((raw >> 11) & 0x1e) | ((raw >> 3) & 0x01)); u8 const g = pal5bit(((raw >> 7) & 0x1e) | ((raw >> 2) & 0x01)); u8 const b = pal5bit(((raw >> 3) & 0x1e) | ((raw >> 1) & 0x01)); return rgb_t(r, g, b); } rgb_t raw_to_rgb_converter::xRGBRRRRGGGGBBBB_bit0_decoder(u32 raw) { u8 const r = pal5bit(((raw >> 7) & 0x1e) | ((raw >> 14) & 0x01)); u8 const g = pal5bit(((raw >> 3) & 0x1e) | ((raw >> 13) & 0x01)); u8 const b = pal5bit(((raw << 1) & 0x1e) | ((raw >> 12) & 0x01)); return rgb_t(r, g, b); } rgb_t raw_to_rgb_converter::xRGBRRRRGGGGBBBB_bit4_decoder(u32 raw) { u8 const r = pal5bit(((raw >> 8) & 0x0f) | ((raw >> 10) & 0x10)); u8 const g = pal5bit(((raw >> 4) & 0x0f) | ((raw >> 9) & 0x10)); u8 const b = pal5bit(((raw >> 0) & 0x0f) | ((raw >> 8) & 0x10)); return rgb_t(r, g, b); } rgb_t raw_to_rgb_converter::xBGRBBBBGGGGRRRR_bit0_decoder(u32 raw) { u8 const r = pal5bit(((raw << 1) & 0x1e) | ((raw >> 12) & 0x01)); u8 const g = pal5bit(((raw >> 3) & 0x1e) | ((raw >> 13) & 0x01)); u8 const b = pal5bit(((raw >> 7) & 0x1e) | ((raw >> 14) & 0x01)); return rgb_t(r, g, b); }