From 803665404e3fbd937f3fcd88a1c363496b4baa11 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 24 Jul 2016 23:53:08 +0000 Subject: [PATCH] Add support for BGR formats to Pixmap, and RGB conversion. The Cairo image surface backend uses the BGR format for "RGB24" for some reason, and we need to handle that. --- src/render/rendergl1.cpp | 3 +++ src/resource.cpp | 52 +++++++++++++++++++++++++++++++++++++--- src/resource.h | 4 +++- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/render/rendergl1.cpp b/src/render/rendergl1.cpp index b08a2548..1864adfd 100644 --- a/src/render/rendergl1.cpp +++ b/src/render/rendergl1.cpp @@ -216,6 +216,9 @@ void OpenGl1Renderer::SelectTexture(std::shared_ptr pm) { case Pixmap::Format::RGBA: format = GL_RGBA; break; case Pixmap::Format::RGB: format = GL_RGB; break; case Pixmap::Format::A: format = GL_ALPHA; break; + case Pixmap::Format::BGRA: + case Pixmap::Format::BGR: + ssassert(false, "Unexpected pixmap format"); } glTexImage2D(GL_TEXTURE_2D, 0, format, pm->width, pm->height, 0, format, GL_UNSIGNED_BYTE, &pm->data[0]); diff --git a/src/resource.cpp b/src/resource.cpp index b5be2724..107047e3 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -65,7 +65,9 @@ std::shared_ptr LoadPng(const std::string &name) { size_t Pixmap::GetBytesPerPixel() const { switch(format) { case Format::RGBA: return 4; + case Format::BGRA: return 4; case Format::RGB: return 3; + case Format::BGR: return 3; case Format::A: return 1; } ssassert(false, "Unexpected pixmap format"); @@ -81,12 +83,52 @@ RgbaColor Pixmap::GetPixel(size_t x, size_t y) const { case Format::RGB: return RgbaColor::From(pixel[0], pixel[1], pixel[2], 255); + case Format::BGRA: + return RgbaColor::From(pixel[2], pixel[1], pixel[0], pixel[3]); + + case Format::BGR: + return RgbaColor::From(pixel[2], pixel[1], pixel[0], 255); + case Format::A: return RgbaColor::From( 255, 255, 255, pixel[0]); } ssassert(false, "Unexpected resource format"); } +void Pixmap::ConvertTo(Format newFormat) { + switch(format) { + case Format::RGBA: + ssassert(newFormat == Format::BGRA, "Unexpected target format"); + break; + + case Format::BGRA: + ssassert(newFormat == Format::RGBA, "Unexpected target format"); + break; + + case Format::RGB: + ssassert(newFormat == Format::BGR, "Unexpected target format"); + break; + + case Format::BGR: + ssassert(newFormat == Format::RGB, "Unexpected target format"); + break; + + case Format::A: + ssassert(false, "Unexpected target format"); + } + + size_t bpp = GetBytesPerPixel(); + for(size_t j = 0; j != height; j++) { + uint8_t *row = &data[j * stride]; + for(size_t i = 0; i != width * bpp; i += bpp) { + // This handles both RGB<>BGR and RGBA<>BGRA. + std::swap(row[i], row[i + 2]); + } + } + + format = newFormat; +} + static std::shared_ptr ReadPngIntoPixmap(png_struct *png_ptr, png_info *info_ptr, bool flip) { png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL); @@ -175,10 +217,13 @@ exit: bool Pixmap::WritePng(FILE *f, bool flip) { int colorType; + bool bgr; switch(format) { - case Format::RGBA: colorType = PNG_COLOR_TYPE_RGBA; break; - case Format::RGB: colorType = PNG_COLOR_TYPE_RGB; break; - case Format::A: ssassert(false, "Unexpected pixmap format"); + case Format::RGBA: colorType = PNG_COLOR_TYPE_RGBA; bgr = false; break; + case Format::BGRA: colorType = PNG_COLOR_TYPE_RGBA; bgr = true; break; + case Format::RGB: colorType = PNG_COLOR_TYPE_RGB; bgr = false; break; + case Format::BGR: colorType = PNG_COLOR_TYPE_RGB; bgr = true; break; + case Format::A: colorType = PNG_COLOR_TYPE_GRAY; bgr = false; break; } std::vector rows; @@ -204,6 +249,7 @@ bool Pixmap::WritePng(FILE *f, bool flip) { png_set_IHDR(png_ptr, info_ptr, width, height, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + if(bgr) png_set_bgr(png_ptr); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, &rows[0]); png_write_end(png_ptr, info_ptr); diff --git a/src/resource.h b/src/resource.h index aab95069..787e2a1f 100644 --- a/src/resource.h +++ b/src/resource.h @@ -24,7 +24,7 @@ std::shared_ptr LoadPng(const std::string &name); class Pixmap { public: - enum class Format { RGBA, RGB, A }; + enum class Format { BGRA, RGBA, BGR, RGB, A }; Format format; size_t width; @@ -40,6 +40,8 @@ public: size_t GetBytesPerPixel() const; RgbaColor GetPixel(size_t x, size_t y) const; + + void ConvertTo(Format newFormat); }; class BitmapFont {