summaryrefslogtreecommitdiff
path: root/vcl/opengl
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2016-04-04 19:27:12 +0900
committerTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2016-04-08 19:10:11 +0900
commit40e9ed91bd8bbfecfc3832d73a81741d0aa97d3a (patch)
treef1405816290ab26dd928b1fa1a699c76ec977ce0 /vcl/opengl
parent96a098c0e8a009b77a26061dac3318da71d34ee4 (diff)
opengl: texture atlas impl. to efficiently packs textures
Change-Id: I66b3eddadb172da26aa1a62f2a795895769db93b
Diffstat (limited to 'vcl/opengl')
-rw-r--r--vcl/opengl/FixedTextureAtlas.cxx20
-rw-r--r--vcl/opengl/PackedTextureAtlas.cxx164
2 files changed, 176 insertions, 8 deletions
diff --git a/vcl/opengl/FixedTextureAtlas.cxx b/vcl/opengl/FixedTextureAtlas.cxx
index 80c1cfe496c7..1ed83111d293 100644
--- a/vcl/opengl/FixedTextureAtlas.cxx
+++ b/vcl/opengl/FixedTextureAtlas.cxx
@@ -42,7 +42,7 @@ void FixedTextureAtlasManager::CreateNewTexture()
mpTextures.back()->InitializeSlots(mWidthFactor * mHeightFactor);
}
-OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+OpenGLTexture FixedTextureAtlasManager::Reserve(int nWidth, int nHeight)
{
ImplOpenGLTexture* pTexture = nullptr;
@@ -71,14 +71,18 @@ OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, in
Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight));
- // If available, copy the image data to the texture
- if (pData)
- {
- if (!pTexture->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData))
- return OpenGLTexture();
- }
-
return OpenGLTexture(pTexture, aRectangle, nSlot);
}
+OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+ OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+ if (pData == nullptr)
+ return aTexture;
+
+ aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+ return aTexture;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/PackedTextureAtlas.cxx b/vcl/opengl/PackedTextureAtlas.cxx
new file mode 100644
index 000000000000..60fa1e98fc41
--- /dev/null
+++ b/vcl/opengl/PackedTextureAtlas.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <sal/config.h>
+#include <vcl/opengl/OpenGLContext.hxx>
+#include <vcl/opengl/OpenGLHelper.hxx>
+
+#include "opengl/framebuffer.hxx"
+#include "opengl/texture.hxx"
+
+#include "opengl/PackedTextureAtlas.hxx"
+
+struct Node
+{
+ Rectangle mRectangle;
+ std::unique_ptr<Node> mLeftNode;
+ std::unique_ptr<Node> mRightNode;
+ bool mOccupied;
+
+ Node(Rectangle& aRectangle);
+
+ bool isLeaf();
+ Node* insert(int nWidth, int nHeight, int nPadding);
+};
+
+Node::Node(Rectangle& aRectangle)
+ : mRectangle(aRectangle)
+ , mLeftNode()
+ , mRightNode()
+ , mOccupied(false)
+{}
+
+bool Node::isLeaf()
+{
+ return mLeftNode.get() == nullptr &&
+ mRightNode.get() == nullptr;
+}
+
+Node* Node::insert(int nWidth, int nHeight, int nPadding)
+{
+ if (!isLeaf())
+ {
+ Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding);
+
+ if (pNewNode != nullptr)
+ return pNewNode;
+
+ return mRightNode->insert(nWidth, nHeight, nPadding);
+ }
+ else
+ {
+ if (mOccupied)
+ {
+ return nullptr;
+ }
+
+ if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight())
+ { // does not fit
+ return nullptr;
+ }
+
+ if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight())
+ { // perfect fit
+ mOccupied = true;
+ return this;
+ }
+
+ int dw = mRectangle.GetWidth() - nWidth;
+ int dh = mRectangle.GetHeight() - nHeight;
+
+ Rectangle aLeftRect;
+ Rectangle aRightRect;
+ if (dw > dh)
+ {
+ aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+ Size(nWidth, mRectangle.GetHeight()));
+ aRightRect = Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
+ Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
+ }
+ else
+ {
+ aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+ Size(mRectangle.GetWidth(), nHeight));
+ aRightRect = Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight),
+ Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding));
+ }
+
+ mLeftNode.reset(new Node(aLeftRect));
+ mRightNode.reset(new Node(aRightRect));
+
+ return mLeftNode->insert(nWidth, nHeight, nPadding);
+ }
+}
+
+struct PackedTexture
+{
+ std::unique_ptr<Node> mpRootNode;
+ ImplOpenGLTexture* mpTexture;
+};
+
+PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight)
+ : mnTextureWidth(nTextureWidth)
+ , mnTextureHeight(nTextureHeight)
+{
+}
+
+PackedTextureAtlasManager::~PackedTextureAtlasManager()
+{
+ for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+ {
+ // Free texture early in VCL shutdown while we have a context.
+ pPackedTexture->mpTexture->Dispose();
+ pPackedTexture->mpTexture->DecreaseRefCount(0);
+ }
+}
+
+void PackedTextureAtlasManager::CreateNewTexture()
+{
+ std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture);
+ pPackedTexture->mpTexture = new ImplOpenGLTexture(mnTextureWidth, mnTextureHeight, true);
+ Rectangle aInitialRect(Point(0, 0), Size(mnTextureWidth, mnTextureHeight));
+ pPackedTexture->mpRootNode.reset(new Node(aInitialRect));
+ maPackedTextures.push_back(std::move(pPackedTexture));
+}
+
+OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight)
+{
+ for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+ {
+ Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+ if (pNode != nullptr)
+ {
+ return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+ }
+ }
+ CreateNewTexture();
+ std::unique_ptr<PackedTexture>& pPackedTexture = maPackedTextures.back();
+ Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+ if (pNode != nullptr)
+ {
+ return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+ }
+ return OpenGLTexture();
+}
+
+OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+ OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+ if (aTexture && pData == nullptr)
+ return aTexture;
+
+ aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+ return aTexture;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */