summaryrefslogtreecommitdiff
path: root/src/player/OffscreenCanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/player/OffscreenCanvas.cpp')
-rw-r--r--src/player/OffscreenCanvas.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/player/OffscreenCanvas.cpp b/src/player/OffscreenCanvas.cpp
new file mode 100644
index 0000000..758bf43
--- /dev/null
+++ b/src/player/OffscreenCanvas.cpp
@@ -0,0 +1,271 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+#include "OffscreenCanvas.h"
+
+#include "CanvasNode.h"
+#include "Player.h"
+
+#include "../base/Exception.h"
+#include "../base/ProfilingZoneID.h"
+#include "../base/ObjectCounter.h"
+#include "../base/ScopeTimer.h"
+
+#include "../graphics/FilterUnmultiplyAlpha.h"
+#include "../graphics/BitmapLoader.h"
+
+#include <iostream>
+
+using namespace boost;
+using namespace std;
+
+namespace avg {
+
+OffscreenCanvas::OffscreenCanvas(Player * pPlayer)
+ : Canvas(pPlayer),
+ m_bIsRendered(false),
+ m_pCameraNodeRef(0)
+{
+ ObjectCounter::get()->incRef(&typeid(*this));
+}
+
+OffscreenCanvas::~OffscreenCanvas()
+{
+ ObjectCounter::get()->decRef(&typeid(*this));
+}
+
+void OffscreenCanvas::setRoot(NodePtr pRootNode)
+{
+ Canvas::setRoot(pRootNode);
+ if (!getRootNode()) {
+ throw (Exception(AVG_ERR_XML_PARSE,
+ "Root node of a canvas tree needs to be a <canvas> node."));
+ }
+}
+
+void OffscreenCanvas::initPlayback()
+{
+ m_bUseMipmaps = getMipmap();
+ PixelFormat pf;
+ if (BitmapLoader::get()->isBlueFirst()) {
+ pf = B8G8R8A8;
+ } else {
+ pf = R8G8B8A8;
+ }
+ bool bUseDepthBuffer = GLContext::getMain()->useDepthBuffer();
+ m_pFBO = FBOPtr(new FBO(getSize(), pf, 1, getMultiSampleSamples(), bUseDepthBuffer,
+ true, m_bUseMipmaps));
+ Canvas::initPlayback(getMultiSampleSamples());
+ m_bIsRendered = false;
+}
+
+void OffscreenCanvas::stopPlayback(bool bIsAbort)
+{
+ m_pFBO = FBOPtr();
+ Canvas::stopPlayback(bIsAbort);
+ m_bIsRendered = false;
+}
+
+BitmapPtr OffscreenCanvas::screenshot() const
+{
+ BitmapPtr pBmp = screenshotIgnoreAlpha();
+ FilterUnmultiplyAlpha().applyInPlace(pBmp);
+ return pBmp;
+}
+
+BitmapPtr OffscreenCanvas::screenshotIgnoreAlpha() const
+{
+ if (!isRunning() || !m_bIsRendered) {
+ throw(Exception(AVG_ERR_UNSUPPORTED,
+ "OffscreenCanvas::screenshot(): Canvas has not been rendered. No screenshot available"));
+ }
+ BitmapPtr pBmp = m_pFBO->getImage(0);
+ return pBmp;
+}
+
+bool OffscreenCanvas::getHandleEvents() const
+{
+ return dynamic_pointer_cast<OffscreenCanvasNode>(getRootNode())->getHandleEvents();
+}
+
+int OffscreenCanvas::getMultiSampleSamples() const
+{
+ return dynamic_pointer_cast<OffscreenCanvasNode>(
+ getRootNode())->getMultiSampleSamples();
+}
+
+bool OffscreenCanvas::getMipmap() const
+{
+ return dynamic_pointer_cast<OffscreenCanvasNode>(getRootNode())->getMipmap();
+}
+
+bool OffscreenCanvas::getAutoRender() const
+{
+ return dynamic_pointer_cast<OffscreenCanvasNode>(getRootNode())->getAutoRender();
+}
+
+void OffscreenCanvas::setAutoRender(bool bAutoRender)
+{
+ dynamic_pointer_cast<OffscreenCanvasNode>(getRootNode())->setAutoRender(bAutoRender);
+}
+
+void OffscreenCanvas::manualRender()
+{
+ emitPreRenderSignal();
+ renderTree();
+ emitFrameEndSignal();
+}
+
+std::string OffscreenCanvas::getID() const
+{
+ return getRootNode()->getID();
+}
+
+bool OffscreenCanvas::isRunning() const
+{
+ return (m_pFBO != FBOPtr());
+}
+
+GLTexturePtr OffscreenCanvas::getTex() const
+{
+ AVG_ASSERT(isRunning());
+ return m_pFBO->getTex();
+}
+
+FBOPtr OffscreenCanvas::getFBO() const
+{
+ AVG_ASSERT(isRunning());
+ return m_pFBO;
+}
+
+void OffscreenCanvas::registerCameraNode(CameraNode* pCameraNode)
+{
+ m_pCameraNodeRef = pCameraNode;
+ m_pCameraNodeRef->setAutoUpdateCameraImage(false);
+}
+
+void OffscreenCanvas::unregisterCameraNode()
+{
+ m_pCameraNodeRef->setAutoUpdateCameraImage(true);
+ m_pCameraNodeRef = NULL;
+}
+
+void OffscreenCanvas::updateCameraImage()
+{
+ m_pCameraNodeRef->updateCameraImage();
+}
+
+bool OffscreenCanvas::hasRegisteredCamera() const
+{
+ return m_pCameraNodeRef != NULL;
+}
+
+bool OffscreenCanvas::isCameraImageAvailable() const
+{
+ if (!hasRegisteredCamera()) {
+ return false;
+ }
+ return m_pCameraNodeRef->isImageAvailable();
+}
+
+void OffscreenCanvas::addDependentCanvas(CanvasPtr pCanvas)
+{
+ m_pDependentCanvases.push_back(pCanvas);
+ try {
+ Player::get()->newCanvasDependency();
+ } catch (Exception&) {
+ m_pDependentCanvases.pop_back();
+ throw;
+ }
+}
+
+void OffscreenCanvas::removeDependentCanvas(CanvasPtr pCanvas)
+{
+ for (unsigned i = 0; i < m_pDependentCanvases.size(); ++i) {
+ if (pCanvas == m_pDependentCanvases[i]) {
+ m_pDependentCanvases.erase(m_pDependentCanvases.begin()+i);
+// dump();
+ return;
+ }
+ }
+ AVG_ASSERT(false);
+}
+
+const vector<CanvasPtr>& OffscreenCanvas::getDependentCanvases() const
+{
+ return m_pDependentCanvases;
+}
+
+unsigned OffscreenCanvas::getNumDependentCanvases() const
+{
+ return m_pDependentCanvases.size();
+}
+
+bool OffscreenCanvas::isSupported()
+{
+ if (!Player::get()->isPlaying()) {
+ throw(Exception(AVG_ERR_UNSUPPORTED,
+ "OffscreenCanvas::isSupported(): Player.play() needs to be called before support can be queried."));
+ }
+ if (GLContext::getMain()->isGLES()) {
+ return true;
+ } else {
+ return FBO::isFBOSupported() && FBO::isPackedDepthStencilSupported();
+ }
+}
+
+bool OffscreenCanvas::isMultisampleSupported()
+{
+ if (!Player::get()->isPlaying()) {
+ throw(Exception(AVG_ERR_UNSUPPORTED,
+ "OffscreenCanvas::isMultisampleSupported(): Player.play() needs to be called before multisample support can be queried."));
+ }
+
+ return FBO::isMultisampleFBOSupported();
+}
+
+void OffscreenCanvas::dump() const
+{
+ cerr << "Canvas: " << getRootNode()->getID() << endl;
+ for (unsigned i = 0; i < m_pDependentCanvases.size(); ++i) {
+ cerr << " " << m_pDependentCanvases[i]->getRootNode()->getID() << endl;
+ }
+}
+
+static ProfilingZoneID OffscreenRenderProfilingZone("Render OffscreenCanvas");
+
+void OffscreenCanvas::renderTree()
+{
+ if (!isRunning()) {
+ throw(Exception(AVG_ERR_UNSUPPORTED,
+ "OffscreenCanvas::renderTree(): Player.play() needs to be called before rendering offscreen canvases."));
+ }
+ preRender();
+ m_pFBO->activate();
+ {
+ ScopeTimer Timer(OffscreenRenderProfilingZone);
+ Canvas::render(IntPoint(getRootNode()->getSize()), true);
+ }
+ m_pFBO->copyToDestTexture();
+ m_bIsRendered = true;
+}
+
+}