From 61e3ecec7982487f5c70cd4c7368dbc33befc078 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 6 May 2019 19:32:56 +0200 Subject: [PATCH] GraphicsBitmap: Add a new "Indexed8" format that uses a 256-entry palette. These bitmaps should only be used as a source bitmap, we won't support painting into them using Painter. You can however manipulate the raw pixel data. :^) --- SharedGraphics/GraphicsBitmap.cpp | 6 ++++++ SharedGraphics/GraphicsBitmap.h | 27 ++++++++++++++++++++++++++- SharedGraphics/Painter.cpp | 31 ++++++++++++++++++++++++------- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/SharedGraphics/GraphicsBitmap.cpp b/SharedGraphics/GraphicsBitmap.cpp index d6c9feaf6d..e8ec1ea8be 100644 --- a/SharedGraphics/GraphicsBitmap.cpp +++ b/SharedGraphics/GraphicsBitmap.cpp @@ -17,6 +17,8 @@ GraphicsBitmap::GraphicsBitmap(Format format, const Size& size) , m_pitch(round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16)) , m_format(format) { + if (format == Format::Indexed8) + m_palette = new RGBA32[256]; m_data = (RGBA32*)mmap(nullptr, size_in_bytes(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); ASSERT(m_data && m_data != (void*)-1); m_needs_munmap = true; @@ -47,6 +49,7 @@ GraphicsBitmap::GraphicsBitmap(Format format, const Size& size, RGBA32* data) , m_pitch(round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16)) , m_format(format) { + ASSERT(format != Format::Indexed8); } GraphicsBitmap::GraphicsBitmap(Format format, const Size& size, MappedFile&& mapped_file) @@ -56,6 +59,7 @@ GraphicsBitmap::GraphicsBitmap(Format format, const Size& size, MappedFile&& map , m_format(format) , m_mapped_file(move(mapped_file)) { + ASSERT(format != Format::Indexed8); } Retained GraphicsBitmap::create_with_shared_buffer(Format format, Retained&& shared_buffer, const Size& size) @@ -70,6 +74,7 @@ GraphicsBitmap::GraphicsBitmap(Format format, Retained&& shared_bu , m_format(format) , m_shared_buffer(move(shared_buffer)) { + ASSERT(format != Format::Indexed8); } GraphicsBitmap::~GraphicsBitmap() @@ -79,6 +84,7 @@ GraphicsBitmap::~GraphicsBitmap() ASSERT(rc == 0); } m_data = nullptr; + delete [] m_palette; } void GraphicsBitmap::set_mmap_name(const String& name) diff --git a/SharedGraphics/GraphicsBitmap.h b/SharedGraphics/GraphicsBitmap.h index de8630bdf9..7c4b8ca31b 100644 --- a/SharedGraphics/GraphicsBitmap.h +++ b/SharedGraphics/GraphicsBitmap.h @@ -11,7 +11,7 @@ class GraphicsBitmap : public Retainable { public: - enum class Format { Invalid, RGB32, RGBA32 }; + enum class Format { Invalid, RGB32, RGBA32, Indexed8 }; static Retained create(Format, const Size&); static Retained create_wrapper(Format, const Size&, RGBA32*); @@ -23,6 +23,8 @@ public: RGBA32* scanline(int y); const RGBA32* scanline(int y) const; + const byte* bits(int y) const; + Rect rect() const { return { {}, m_size }; } Size size() const { return m_size; } int width() const { return m_size.width(); } @@ -37,6 +39,23 @@ public: size_t size_in_bytes() const { return m_pitch * m_size.height() * sizeof(RGBA32); } + Color palette_color(byte index) const { return Color::from_rgba(m_palette[index]); } + void set_palette_color(byte index, Color color) { m_palette[index] = color.value(); } + + Color get_pixel(int x, int y) const + { + switch (m_format) { + case Format::RGB32: + return Color::from_rgb(scanline(y)[x]); + case Format::RGBA32: + return Color::from_rgba(scanline(y)[x]); + case Format::Indexed8: + return Color::from_rgba(m_palette[bits(y)[x]]); + default: + ASSERT_NOT_REACHED(); + } + } + private: GraphicsBitmap(Format, const Size&); GraphicsBitmap(Format, const Size&, RGBA32*); @@ -45,6 +64,7 @@ private: Size m_size; RGBA32* m_data { nullptr }; + RGBA32* m_palette { nullptr }; size_t m_pitch { 0 }; Format m_format { Format::Invalid }; bool m_needs_munmap { false }; @@ -61,3 +81,8 @@ inline const RGBA32* GraphicsBitmap::scanline(int y) const { return reinterpret_cast((((const byte*)m_data) + (y * m_pitch))); } + +inline const byte* GraphicsBitmap::bits(int y) const +{ + return reinterpret_cast(scanline(y)); +} diff --git a/SharedGraphics/Painter.cpp b/SharedGraphics/Painter.cpp index 32fe9ab1a1..e56eb3bfce 100644 --- a/SharedGraphics/Painter.cpp +++ b/SharedGraphics/Painter.cpp @@ -308,15 +308,32 @@ void Painter::blit(const Point& position, const GraphicsBitmap& source, const Re const int last_row = clipped_rect.bottom() - dst_rect.top(); const int first_column = clipped_rect.left() - dst_rect.left(); RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x(); - const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column; const size_t dst_skip = m_target->pitch() / sizeof(RGBA32); - const size_t src_skip = source.pitch() / sizeof(RGBA32); - for (int row = first_row; row <= last_row; ++row) { - fast_dword_copy(dst, src, clipped_rect.width()); - dst += dst_skip; - src += src_skip; + if (source.format() == GraphicsBitmap::Format::RGB32 || source.format() == GraphicsBitmap::Format::RGBA32) { + const RGBA32* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column; + const size_t src_skip = source.pitch() / sizeof(RGBA32); + for (int row = first_row; row <= last_row; ++row) { + fast_dword_copy(dst, src, clipped_rect.width()); + dst += dst_skip; + src += src_skip; + } + return; } + + if (source.format() == GraphicsBitmap::Format::Indexed8) { + const byte* src = source.bits(src_rect.top() + first_row) + src_rect.left() + first_column; + const size_t src_skip = source.pitch(); + for (int row = first_row; row <= last_row; ++row) { + for (int i = 0; i < clipped_rect.width(); ++i) + dst[i] = source.palette_color(src[i]).value(); + dst += dst_skip; + src += src_skip; + } + return; + } + + ASSERT_NOT_REACHED(); } void Painter::draw_scaled_bitmap(const Rect& a_dst_rect, const GraphicsBitmap& source, const Rect& src_rect) @@ -345,7 +362,7 @@ void Painter::draw_scaled_bitmap(const Rect& a_dst_rect, const GraphicsBitmap& s auto scaled_x = (float)(x - dst_rect.x()) * hscale; auto scaled_y = (float)(y - dst_rect.y()) * vscale; - auto src_pixel = Color::from_rgba(source.scanline((int)scaled_y)[(int)scaled_x]); + auto src_pixel = source.get_pixel(scaled_x, scaled_y); if (!src_pixel.alpha()) continue;