From 497b41d6d82e494ab0d06ce4996c50b434a421ce Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 12 Jan 2018 14:36:25 +0100 Subject: [PATCH] workaround to create images with transparent background --- src/Gui/SoFCOffscreenRenderer.cpp | 49 ++++++++++++++++++++++++++----- src/Gui/SoFCOffscreenRenderer.h | 1 + src/Gui/View3DInventorViewer.cpp | 31 ++++++++++++++++--- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/Gui/SoFCOffscreenRenderer.cpp b/src/Gui/SoFCOffscreenRenderer.cpp index ad28b3cebf..b237a08800 100644 --- a/src/Gui/SoFCOffscreenRenderer.cpp +++ b/src/Gui/SoFCOffscreenRenderer.cpp @@ -478,6 +478,9 @@ void SoQtOffscreenRenderer::setBackgroundColor(const SbColor4f & color) { PRIVATE(this)->backgroundcolor = color; + PRIVATE(this)->backgroundopaque = color; + if (color[3] < 1.0) + PRIVATE(this)->backgroundopaque.setValue(1,1,1,1); } /*! @@ -556,8 +559,11 @@ SoQtOffscreenRenderer::makePixelBuffer(int width, int height, int samples) viewport.setWindowSize(width, height); QGLFormat fmt; - //With enabled alpha a transparent background is supported but - //at the same time breaks semi-transparent models + // With enabled alpha a transparent background is supported but + // at the same time breaks semi-transparent models. A workaround + // is to use a certain background color using GL_RGB as texture + // format and in the output image search for the above color and + // replaces it with the color requested by the user. //fmt.setAlpha(true); if (samples > 0) { fmt.setSampleBuffers(true); @@ -586,8 +592,11 @@ SoQtOffscreenRenderer::makeFrameBuffer(int width, int height, int samples) QtGLFramebufferObjectFormat fmt; fmt.setSamples(samples); fmt.setAttachment(QtGLFramebufferObject::Depth); - //With enabled alpha a transparent background is supported but - //at the same time breaks semi-transparent models + // With enabled alpha a transparent background is supported but + // at the same time breaks semi-transparent models. A workaround + // is to use a certain background color using GL_RGB as texture + // format and in the output image search for the above color and + // replaces it with the color requested by the user. #if defined(HAVE_QT5_OPENGL) //fmt.setInternalTextureFormat(GL_RGBA32F_ARB); fmt.setInternalTextureFormat(GL_RGB32F_ARB); @@ -654,10 +663,10 @@ SoQtOffscreenRenderer::renderFromBase(SoBase * base) this->renderaction->setCacheContext(cache_context); glEnable(GL_DEPTH_TEST); - glClearColor(this->backgroundcolor[0], - this->backgroundcolor[1], - this->backgroundcolor[2], - this->backgroundcolor[3]); + glClearColor(this->backgroundopaque[0], + this->backgroundopaque[1], + this->backgroundopaque[2], + this->backgroundopaque[3]); // needed to clear viewport after glViewport() is called from // SoGLRenderAction @@ -764,6 +773,30 @@ SoQtOffscreenRenderer::writeToImage (QImage& img) const #else img = this->glImage; #endif + if (PRIVATE(this)->backgroundcolor[3] < 1.0) { + QColor c1, c2; + c1.setRedF(PRIVATE(this)->backgroundcolor[0]); + c1.setGreenF(PRIVATE(this)->backgroundcolor[1]); + c1.setBlueF(PRIVATE(this)->backgroundcolor[2]); + c1.setAlphaF(PRIVATE(this)->backgroundcolor[3]); + c2.setRedF(PRIVATE(this)->backgroundopaque[0]); + c2.setGreenF(PRIVATE(this)->backgroundopaque[1]); + c2.setBlueF(PRIVATE(this)->backgroundopaque[2]); + c2.setAlphaF(PRIVATE(this)->backgroundopaque[3]); + + QRgb rgba = c1.rgba(); + QRgb rgb = c2.rgb(); + QRgb * bits = (QRgb*) img.bits(); + int height = img.height(); + int width = img.width(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (*bits == rgb) + *bits = rgba; + bits++; + } + } + } } /*! diff --git a/src/Gui/SoFCOffscreenRenderer.h b/src/Gui/SoFCOffscreenRenderer.h index cf6e3c26ab..11465e79d6 100644 --- a/src/Gui/SoFCOffscreenRenderer.h +++ b/src/Gui/SoFCOffscreenRenderer.h @@ -143,6 +143,7 @@ private: SbViewportRegion viewport; SbColor4f backgroundcolor; + SbColor4f backgroundopaque; SoGLRenderAction * renderaction; SbBool didallocation; SbBool pbuffer; diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index e5264a5c40..8ac96ebe2b 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -1420,8 +1420,11 @@ void View3DInventorViewer::imageFromFramebuffer(int width, int height, int sampl QtGLFramebufferObjectFormat fboFormat; fboFormat.setSamples(samples); fboFormat.setAttachment(QtGLFramebufferObject::Depth); - //With enabled alpha a transparent background is supported but - //at the same time breaks semi-transparent models + // With enabled alpha a transparent background is supported but + // at the same time breaks semi-transparent models. A workaround + // is to use a certain background color using GL_RGB as texture + // format and in the output image search for the above color and + // replaces it with the color requested by the user. #if defined(HAVE_QT5_OPENGL) //fboFormat.setInternalTextureFormat(GL_RGBA32F_ARB); fboFormat.setInternalTextureFormat(GL_RGB32F_ARB); @@ -1434,8 +1437,14 @@ void View3DInventorViewer::imageFromFramebuffer(int width, int height, int sampl const QColor col = backgroundColor(); bool on = hasGradientBackground(); - if (bgcolor.isValid()) { - setBackgroundColor(bgcolor); + int alpha = 255; + QColor bgopaque = bgcolor; + if (bgopaque.isValid()) { + // force an opaque background color + alpha = bgopaque.alpha(); + if (alpha < 255) + bgopaque.setRgb(255,255,255); + setBackgroundColor(bgopaque); setGradientBackground(false); } @@ -1443,6 +1452,20 @@ void View3DInventorViewer::imageFromFramebuffer(int width, int height, int sampl setBackgroundColor(col); setGradientBackground(on); img = fbo.toImage(); + + // if background color isn't opaque manipulate the image + if (alpha < 255) { + QRgb rgba = bgcolor.rgba(); + QRgb rgb = bgopaque.rgb(); + QRgb * bits = (QRgb*) img.bits(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (*bits == rgb) + *bits = rgba; + bits++; + } + } + } } void View3DInventorViewer::renderToFramebuffer(QtGLFramebufferObject* fbo)