Procházet zdrojové kódy

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. :^)
Andreas Kling před 6 roky
rodič
revize
61e3ecec79

+ 6 - 0
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> GraphicsBitmap::create_with_shared_buffer(Format format, Retained<SharedBuffer>&& shared_buffer, const Size& size)
@@ -70,6 +74,7 @@ GraphicsBitmap::GraphicsBitmap(Format format, Retained<SharedBuffer>&& 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)

+ 26 - 1
SharedGraphics/GraphicsBitmap.h

@@ -11,7 +11,7 @@
 
 class GraphicsBitmap : public Retainable<GraphicsBitmap> {
 public:
-    enum class Format { Invalid, RGB32, RGBA32 };
+    enum class Format { Invalid, RGB32, RGBA32, Indexed8 };
 
     static Retained<GraphicsBitmap> create(Format, const Size&);
     static Retained<GraphicsBitmap> 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 RGBA32*>((((const byte*)m_data) + (y * m_pitch)));
 }
+
+inline const byte* GraphicsBitmap::bits(int y) const
+{
+    return reinterpret_cast<const byte*>(scanline(y));
+}

+ 24 - 7
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;