From 0128baddff58ce3fc4eab843c4b00a21bfed0ce3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 31 Aug 2016 17:34:31 +0200 Subject: [PATCH] #279 Use frame buffer objects for snapshots when available, otherwise use grabFrameBuffer() --- .../Application/RiaApplication.cpp | 68 +++++++++++++--- ApplicationCode/Application/RiaApplication.h | 3 + .../RicSnapshotViewToClipboardFeature.cpp | 37 +-------- ApplicationCode/ProjectDataModel/RimView.cpp | 11 +-- ApplicationCode/ProjectDataModel/RimView.h | 4 +- Fwk/AppFwk/cafViewer/cafViewer.cpp | 79 +++++++++++++++++-- Fwk/AppFwk/cafViewer/cafViewer.h | 9 ++- 7 files changed, 145 insertions(+), 66 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index c2212d6f35..4d06a6091d 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -108,6 +108,8 @@ #ifdef WIN32 #include #endif +#include "RiuSummaryQwtPlot.h" +#include "RiuWellLogPlot.h" namespace caf { @@ -1392,6 +1394,43 @@ RiuMainPlotWindow* RiaApplication::mainPlotWindow() return m_mainPlotWindow; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimViewWindow* RiaApplication::activeViewWindow() +{ + RimViewWindow* viewWindow = NULL; + + QWidget* topLevelWidget = RiaApplication::activeWindow(); + + if (dynamic_cast(topLevelWidget)) + { + viewWindow = RiaApplication::instance()->activeReservoirView(); + } + + if (dynamic_cast(topLevelWidget)) + { + RiuMainPlotWindow* mainPlotWindow = dynamic_cast(topLevelWidget); + QList subwindows = mainPlotWindow->subWindowList(QMdiArea::StackingOrder); + if (subwindows.size() > 0) + { + RiuSummaryQwtPlot* summaryQwtPlot = dynamic_cast(subwindows.back()->widget()); + if (summaryQwtPlot) + { + viewWindow = summaryQwtPlot->ownerPlotDefinition(); + } + + RiuWellLogPlot* wellLogPlot = dynamic_cast(subwindows.back()->widget()); + if (wellLogPlot) + { + viewWindow = wellLogPlot->ownerPlotDefinition(); + } + } + } + + return viewWindow; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1777,9 +1816,9 @@ void RiaApplication::saveSnapshotAs(const QString& fileName) //-------------------------------------------------------------------------------------------------- void RiaApplication::copySnapshotToClipboard() { - QClipboard* clipboard = QApplication::clipboard(); - if (clipboard) - { + QClipboard* clipboard = QApplication::clipboard(); + if (clipboard) + { QImage image = grabFrameBufferImage(); if (!image.isNull()) { @@ -2160,21 +2199,26 @@ cvf::Font* RiaApplication::customFont() //-------------------------------------------------------------------------------------------------- QImage RiaApplication::grabFrameBufferImage() { + // TODO: Create a general solution that also works with well log plots and summary plots + // For now, only reservoir views are supported by this solution + /* + RimViewWindow* viewWindow = RiaApplication::activeViewWindow(); + if (viewWindow) + { + return viewWindow->snapshotWindowContent(); + } + + return QImage(); + */ + QImage image; if (m_activeReservoirView && m_activeReservoirView->viewer()) { - m_activeReservoirView->viewer()->repaint(); - - GLint currentReadBuffer; - glGetIntegerv(GL_READ_BUFFER, ¤tReadBuffer); - - glReadBuffer(GL_FRONT); - image = m_activeReservoirView->viewer()->grabFrameBuffer(); - - glReadBuffer(currentReadBuffer); + return m_activeReservoirView->snapshotWindowContent(); } return image; + } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/RiaApplication.h b/ApplicationCode/Application/RiaApplication.h index 439d2c9181..ccc1a26276 100644 --- a/ApplicationCode/Application/RiaApplication.h +++ b/ApplicationCode/Application/RiaApplication.h @@ -48,6 +48,7 @@ class RimEclipseView; class RimProject; class RimSummaryPlot; class RimView; +class RimViewWindow; class RimWellLogPlot; class RiuMainPlotWindow; @@ -178,6 +179,8 @@ public: RiuMainPlotWindow* getOrCreateAndShowMainPlotWindow(); RiuMainPlotWindow* mainPlotWindow(); + static RimViewWindow* activeViewWindow(); + private: enum ProjectLoadAction { diff --git a/ApplicationCode/Commands/RicSnapshotViewToClipboardFeature.cpp b/ApplicationCode/Commands/RicSnapshotViewToClipboardFeature.cpp index b4455e8047..6345cecc10 100644 --- a/ApplicationCode/Commands/RicSnapshotViewToClipboardFeature.cpp +++ b/ApplicationCode/Commands/RicSnapshotViewToClipboardFeature.cpp @@ -20,15 +20,7 @@ #include "RiaApplication.h" -#include "RimSummaryPlot.h" -#include "RimView.h" #include "RimViewWindow.h" -#include "RimWellLogPlot.h" - -#include "RiuMainPlotWindow.h" -#include "RiuMainWindow.h" -#include "RiuSummaryQwtPlot.h" -#include "RiuWellLogPlot.h" #include #include @@ -49,34 +41,7 @@ bool RicSnapshotViewToClipboardFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicSnapshotViewToClipboardFeature::onActionTriggered(bool isChecked) { - RimViewWindow* viewWindow = NULL; - - QWidget* topLevelWidget = RiaApplication::activeWindow(); - - if (dynamic_cast(topLevelWidget)) - { - viewWindow = RiaApplication::instance()->activeReservoirView(); - } - - if (dynamic_cast(topLevelWidget)) - { - RiuMainPlotWindow* mainPlotWindow = dynamic_cast(topLevelWidget); - QList subwindows = mainPlotWindow->subWindowList(QMdiArea::StackingOrder); - if (subwindows.size() > 0) - { - RiuSummaryQwtPlot* summaryQwtPlot = dynamic_cast(subwindows.back()->widget()); - if (summaryQwtPlot) - { - viewWindow = summaryQwtPlot->ownerPlotDefinition(); - } - - RiuWellLogPlot* wellLogPlot = dynamic_cast(subwindows.back()->widget()); - if (wellLogPlot) - { - viewWindow = wellLogPlot->ownerPlotDefinition(); - } - } - } + RimViewWindow* viewWindow = RiaApplication::activeViewWindow(); if (viewWindow) { diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 411ac37dd0..bb37faeeb2 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -255,21 +255,14 @@ void RimView::updateViewerWidget() //-------------------------------------------------------------------------------------------------- QImage RimView::snapshotWindowContent() { - QImage image; if (m_viewer) { m_viewer->repaint(); - GLint currentReadBuffer; - glGetIntegerv(GL_READ_BUFFER, ¤tReadBuffer); - - glReadBuffer(GL_FRONT); - image = m_viewer->grabFrameBuffer(); - - glReadBuffer(currentReadBuffer); + return m_viewer->snapshotImage(); } - return image; + return QImage(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 86bf2ff715..f315952066 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -154,6 +154,7 @@ public: void selectOverlayInfoConfig(); + virtual QImage snapshotWindowContent() override; virtual void zoomAll() override; @@ -197,9 +198,6 @@ protected: virtual void resetLegendsInViewer() = 0; virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility) = 0; - virtual QImage snapshotWindowContent() override; - - QPointer m_viewer; caf::PdmField m_currentTimeStep; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 11d0779b5c..20eac73049 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -46,9 +46,11 @@ #include "cvfDrawable.h" #include "cvfDrawableGeo.h" #include "cvfDynamicUniformSet.h" +#include "cvfFramebufferObject.h" #include "cvfHitItemCollection.h" #include "cvfManipulatorTrackball.h" #include "cvfModel.h" +#include "cvfOpenGLCapabilities.h" #include "cvfOpenGLResourceManager.h" #include "cvfOverlayImage.h" #include "cvfPart.h" @@ -56,8 +58,11 @@ #include "cvfRayIntersectSpec.h" #include "cvfRenderQueueSorter.h" #include "cvfRenderSequence.h" +#include "cvfRenderbufferObject.h" #include "cvfRendering.h" #include "cvfScene.h" +#include "cvfShaderSourceProvider.h" +#include "cvfSingleQuadRenderingGenerator.h" #include "cvfTextureImage.h" #include "cvfTransform.h" #include "cvfUniform.h" @@ -184,6 +189,20 @@ void caf::Viewer::setupMainRendering() m_mainRendering->renderEngine()->enableForcedImmediateMode(true); } + if (contextGroup()->capabilities() && + contextGroup()->capabilities()->hasCapability(cvf::OpenGLCapabilities::FRAMEBUFFER_OBJECT)) + { + m_offscreenFbo = new cvf::FramebufferObject; + m_mainRendering->setTargetFramebuffer(m_offscreenFbo.p()); + + cvf::ref rbo = new cvf::RenderbufferObject(cvf::RenderbufferObject::DEPTH_COMPONENT24, 1, 1); + m_offscreenFbo->attachDepthRenderbuffer(rbo.p()); + + m_offscreenTexture = new cvf::Texture(cvf::Texture::TEXTURE_2D, cvf::Texture::RGBA); + m_offscreenTexture->setSize(1, 1); + m_offscreenFbo->attachColorTexture2d(0, m_offscreenTexture.p()); + } + updateOverlayImagePresence(); } @@ -192,7 +211,25 @@ void caf::Viewer::setupMainRendering() //-------------------------------------------------------------------------------------------------- void caf::Viewer::setupRenderingSequence() { - m_renderingSequence->addRendering(m_mainRendering.p()); + m_renderingSequence->addRendering(m_mainRendering.p()); + + if (m_offscreenFbo.notNull()) + { + // Setup second rendering drawing the texture on the screen + // ------------------------------------------------------------------------- + cvf::SingleQuadRenderingGenerator quadRenderGen; + cvf::ref sampler = new cvf::Sampler; + sampler->setWrapMode(cvf::Sampler::CLAMP_TO_EDGE); + sampler->setMinFilter(cvf::Sampler::NEAREST); + sampler->setMagFilter(cvf::Sampler::NEAREST); + + quadRenderGen.addTexture(m_offscreenTexture.p(), sampler.p(), "u_texture2D"); + quadRenderGen.addFragmentShaderCode(cvf::ShaderSourceProvider::instance()->getSourceFromRepository(cvf::ShaderSourceRepository::fs_Unlit)); + quadRenderGen.addFragmentShaderCode(cvf::ShaderSourceProvider::instance()->getSourceFromRepository(cvf::ShaderSourceRepository::src_Texture)); + + cvf::ref quadRendering = quadRenderGen.generate(); + m_renderingSequence->addRendering(quadRendering.p()); + } updateCamera(width(), height()); } @@ -277,7 +314,6 @@ void caf::Viewer::updateCamera(int width, int height) } } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -464,6 +500,16 @@ void caf::Viewer::resizeGL(int width, int height) { if (width < 1 || height < 1) return; + if (m_offscreenFbo.notNull()) + { + m_offscreenFbo->resizeAttachedBuffers(width, height); + + CVF_ASSERT(m_renderingSequence->renderingCount() > 1); + + cvf::ref quadRendering = m_renderingSequence->rendering(1); + quadRendering->camera()->viewport()->set(0, 0, width, height); + } + updateCamera(width, height); } @@ -476,7 +522,6 @@ void caf::Viewer::enablePerfInfoHud(bool enable) updateOverlayImagePresence(); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -485,8 +530,6 @@ bool caf::Viewer::isPerfInfoHudEnabled() return m_showPerfInfoHud; } - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -772,6 +815,32 @@ bool caf::Viewer::isShadersSupported() return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage caf::Viewer::snapshotImage() +{ + QImage image; + if (m_offscreenTexture.notNull() && m_offscreenTexture->image()) + { + image = cvfqt::Utils::toQImage(*(m_offscreenTexture->image())); + } + else + { + // Code moved from RimView::snapshotWindowContent() + + GLint currentReadBuffer; + glGetIntegerv(GL_READ_BUFFER, ¤tReadBuffer); + + glReadBuffer(GL_FRONT); + image = this->grabFrameBuffer(); + + glReadBuffer(currentReadBuffer); + } + + return image; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index d0919200d5..52eb2e8720 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -49,15 +49,17 @@ namespace cvf { class Camera; + class FramebufferObject; class HitItemCollection; class Model; class OverlayImage; + class OverlayItem; class OverlayScalarMapperLegend; class RenderSequence; class Rendering; class Scene; + class Texture; class TextureImage; - class OverlayItem; } namespace caf { @@ -150,6 +152,7 @@ public: // Find out whether the system supports shaders static bool isShadersSupported(); + QImage snapshotImage(); public slots: virtual void slotSetCurrentFrame(int frameIndex); @@ -224,6 +227,10 @@ private: // Parallel projection light modification cvf::ref m_globalUniformSet; + + // Offscreen render objects + cvf::ref m_offscreenFbo; + cvf::ref m_offscreenTexture; }; } // End namespace caf