summaryrefslogtreecommitdiff
path: root/src/player/Image.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/player/Image.cpp')
-rw-r--r--src/player/Image.cpp399
1 files changed, 399 insertions, 0 deletions
diff --git a/src/player/Image.cpp b/src/player/Image.cpp
new file mode 100644
index 0000000..5ac5fb9
--- /dev/null
+++ b/src/player/Image.cpp
@@ -0,0 +1,399 @@
+//
+// 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 "Image.h"
+
+#include "../base/Logger.h"
+#include "../base/Exception.h"
+#include "../base/ObjectCounter.h"
+
+#include "../graphics/Filterfliprgb.h"
+#include "../graphics/TextureMover.h"
+#include "../graphics/BitmapLoader.h"
+
+#include "OGLSurface.h"
+#include "OffscreenCanvas.h"
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+namespace avg {
+
+Image::Image(OGLSurface * pSurface, const MaterialInfo& material)
+ : m_sFilename(""),
+ m_pSurface(pSurface),
+ m_State(CPU),
+ m_Source(NONE),
+ m_Material(material)
+{
+ ObjectCounter::get()->incRef(&typeid(*this));
+ assertValid();
+}
+
+Image::~Image()
+{
+ if (m_State == GPU && m_Source != NONE) {
+ m_pSurface->destroy();
+ }
+ ObjectCounter::get()->decRef(&typeid(*this));
+}
+
+void Image::moveToGPU()
+{
+ assertValid();
+ if (m_State == CPU) {
+ switch (m_Source) {
+ case FILE:
+ case BITMAP:
+ setupSurface();
+ break;
+ case SCENE:
+ m_pSurface->create(B8G8R8X8, m_pCanvas->getTex());
+ break;
+ case NONE:
+ break;
+ default:
+ AVG_ASSERT(false);
+ }
+ m_State = GPU;
+ }
+ assertValid();
+}
+
+void Image::moveToCPU()
+{
+ assertValid();
+ if (m_State == GPU) {
+ switch (m_Source) {
+ case FILE:
+ case BITMAP:
+ m_pBmp = m_pSurface->getTex()->moveTextureToBmp();
+ break;
+ case SCENE:
+ break;
+ case NONE:
+ break;
+ default:
+ AVG_ASSERT(false);
+ return;
+ }
+ m_State = CPU;
+ m_pSurface->destroy();
+ }
+ assertValid();
+}
+
+void Image::discard()
+{
+ assertValid();
+ setEmpty();
+ m_State = CPU;
+ assertValid();
+}
+
+void Image::setEmpty()
+{
+ assertValid();
+ if (m_State == GPU) {
+ m_pSurface->destroy();
+ }
+ changeSource(NONE);
+ assertValid();
+}
+
+void Image::setFilename(const std::string& sFilename, TextureCompression comp)
+{
+ assertValid();
+ AVG_TRACE(Logger::category::MEMORY, Logger::severity::INFO, "Loading " << sFilename);
+ BitmapPtr pBmp = loadBitmap(sFilename);
+ if (comp == TEXTURECOMPRESSION_B5G6R5 && pBmp->hasAlpha()) {
+ throw Exception(AVG_ERR_UNSUPPORTED,
+ "B5G6R5-compressed textures with an alpha channel are not supported.");
+ }
+ changeSource(FILE);
+ m_pBmp = pBmp;
+
+ m_sFilename = sFilename;
+
+ switch (comp) {
+ case TEXTURECOMPRESSION_B5G6R5:
+ m_pBmp = BitmapPtr(new Bitmap(pBmp->getSize(), B5G6R5, sFilename));
+ if (!BitmapLoader::get()->isBlueFirst()) {
+ FilterFlipRGB().applyInPlace(pBmp);
+ }
+ m_pBmp->copyPixels(*pBmp);
+ break;
+ case TEXTURECOMPRESSION_NONE:
+ break;
+ default:
+ assert(false);
+ }
+
+ if (m_State == GPU) {
+ m_pSurface->destroy();
+ setupSurface();
+ }
+ assertValid();
+}
+
+void Image::setBitmap(BitmapPtr pBmp, TextureCompression comp)
+{
+ assertValid();
+ if (!pBmp) {
+ throw Exception(AVG_ERR_UNSUPPORTED, "setBitmap(): bitmap must not be None!");
+ }
+ if (comp == TEXTURECOMPRESSION_B5G6R5 && pBmp->hasAlpha()) {
+ throw Exception(AVG_ERR_UNSUPPORTED,
+ "B5G6R5-compressed textures with an alpha channel are not supported.");
+ }
+ bool bSourceChanged = changeSource(BITMAP);
+ PixelFormat pf;
+ switch (comp) {
+ case TEXTURECOMPRESSION_NONE:
+ pf = pBmp->getPixelFormat();
+ break;
+ case TEXTURECOMPRESSION_B5G6R5:
+ pf = B5G6R5;
+ if (!BitmapLoader::get()->isBlueFirst()) {
+ FilterFlipRGB().applyInPlace(pBmp);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ if (m_State == GPU) {
+ GLTexturePtr pTex = m_pSurface->getTex();
+ if (bSourceChanged || m_pSurface->getSize() != pBmp->getSize() ||
+ m_pSurface->getPixelFormat() != pf)
+ {
+ pTex = GLTexturePtr(new GLTexture(pBmp->getSize(), pf,
+ m_Material.getUseMipmaps(), 0, m_Material.getWrapSMode(),
+ m_Material.getWrapTMode()));
+ m_pSurface->create(pf, pTex);
+ }
+ TextureMoverPtr pMover = TextureMover::create(pBmp->getSize(), pf,
+ GL_STATIC_DRAW);
+ BitmapPtr pMoverBmp = pMover->lock();
+ pMoverBmp->copyPixels(*pBmp);
+ pMover->unlock();
+ pMover->moveToTexture(*pTex);
+ m_pBmp = BitmapPtr();
+ } else {
+ m_pBmp = BitmapPtr(new Bitmap(pBmp->getSize(), pf, ""));
+ m_pBmp->copyPixels(*pBmp);
+ }
+ assertValid();
+}
+
+void Image::setCanvas(OffscreenCanvasPtr pCanvas)
+{
+ assertValid();
+ if (m_Source == SCENE && pCanvas == m_pCanvas) {
+ return;
+ }
+ changeSource(SCENE);
+ m_pCanvas = pCanvas;
+ if (m_State == GPU) {
+ m_pSurface->create(B8G8R8X8, m_pCanvas->getTex());
+ }
+ assertValid();
+}
+
+OffscreenCanvasPtr Image::getCanvas() const
+{
+ return m_pCanvas;
+}
+
+const string& Image::getFilename() const
+{
+ return m_sFilename;
+}
+
+BitmapPtr Image::getBitmap()
+{
+ if (m_Source == NONE) {
+ return BitmapPtr();
+ } else {
+ switch (m_State) {
+ case CPU:
+ if (m_Source == SCENE) {
+ return BitmapPtr();
+ } else {
+ return BitmapPtr(new Bitmap(*m_pBmp));
+ }
+ case GPU:
+ return m_pSurface->getTex()->moveTextureToBmp();
+ default:
+ AVG_ASSERT(false);
+ return BitmapPtr();
+ }
+ }
+}
+
+IntPoint Image::getSize()
+{
+ if (m_Source == NONE) {
+ return IntPoint(0,0);
+ } else {
+ switch (m_State) {
+ case CPU:
+ if (m_Source == SCENE) {
+ return m_pCanvas->getSize();
+ } else {
+ return m_pBmp->getSize();
+ }
+ case GPU:
+ return m_pSurface->getSize();
+ default:
+ AVG_ASSERT(false);
+ return IntPoint(0,0);
+ }
+ }
+}
+
+PixelFormat Image::getPixelFormat()
+{
+ PixelFormat pf;
+ if (BitmapLoader::get()->isBlueFirst()) {
+ pf = B8G8R8X8;
+ } else {
+ pf = R8G8B8X8;
+ }
+ if (m_Source != NONE) {
+ switch (m_State) {
+ case CPU:
+ if (m_Source != SCENE) {
+ pf = m_pBmp->getPixelFormat();
+ }
+ case GPU:
+ pf = m_pSurface->getPixelFormat();
+ default:
+ AVG_ASSERT(false);
+ }
+ }
+ return pf;
+}
+
+OGLSurface* Image::getSurface()
+{
+ AVG_ASSERT(m_State == GPU);
+ return m_pSurface;
+}
+
+Image::State Image::getState()
+{
+ return m_State;
+}
+
+Image::Source Image::getSource()
+{
+ return m_Source;
+}
+
+Image::TextureCompression Image::string2compression(const string& s)
+{
+ if (s == "none") {
+ return Image::TEXTURECOMPRESSION_NONE;
+ } else if (s == "B5G6R5") {
+ return Image::TEXTURECOMPRESSION_B5G6R5;
+ } else {
+ throw(Exception(AVG_ERR_UNSUPPORTED,
+ "Image compression "+s+" not supported."));
+ }
+}
+
+string Image::compression2String(TextureCompression compression)
+{
+ switch(compression) {
+ case Image::TEXTURECOMPRESSION_NONE:
+ return "none";
+ case Image::TEXTURECOMPRESSION_B5G6R5:
+ return "B5G6R5";
+ default:
+ AVG_ASSERT(false);
+ return 0;
+ }
+}
+
+void Image::setupSurface()
+{
+ PixelFormat pf = m_pBmp->getPixelFormat();
+// cerr << "setupSurface: " << pf << endl;
+ GLTexturePtr pTex(new GLTexture(m_pBmp->getSize(), pf, m_Material.getUseMipmaps(),
+ 0, m_Material.getWrapSMode(), m_Material.getWrapTMode()));
+ m_pSurface->create(pf, pTex);
+ TextureMoverPtr pMover = TextureMover::create(m_pBmp->getSize(), pf, GL_STATIC_DRAW);
+ pMover->moveBmpToTexture(m_pBmp, *pTex);
+ m_pBmp = BitmapPtr();
+}
+
+bool Image::changeSource(Source newSource)
+{
+ if (newSource != m_Source) {
+ switch (m_Source) {
+ case NONE:
+ break;
+ case FILE:
+ case BITMAP:
+ if (m_State == CPU) {
+ m_pBmp = BitmapPtr();
+ }
+ m_sFilename = "";
+ break;
+ case SCENE:
+ m_pCanvas = OffscreenCanvasPtr();
+ break;
+ default:
+ AVG_ASSERT(false);
+ }
+ m_Source = newSource;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void Image::assertValid() const
+{
+ AVG_ASSERT(m_pSurface);
+ AVG_ASSERT((m_Source == FILE) == (m_sFilename != ""));
+ AVG_ASSERT((m_Source == SCENE) == bool(m_pCanvas));
+ switch (m_State) {
+ case CPU:
+ AVG_ASSERT((m_Source == FILE || m_Source == BITMAP) == bool(m_pBmp));
+ AVG_ASSERT(!(m_pSurface->isCreated()));
+ break;
+ case GPU:
+ AVG_ASSERT(!m_pBmp);
+ if (m_Source != NONE) {
+ AVG_ASSERT(m_pSurface->isCreated());
+ } else {
+ AVG_ASSERT(!m_pSurface->isCreated());
+ }
+ break;
+ default:
+ AVG_ASSERT(false);
+ }
+}
+
+}