Version 5.2.0.0.beta1, tag libreoffice-5.2.0.0.beta1
[LibreOffice.git] / vcl / opengl / PackedTextureAtlas.cxx
blob38475b1b3bdb34a3c3414967545a0639e53569f2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <sal/config.h>
12 #include <vcl/opengl/OpenGLContext.hxx>
13 #include <vcl/opengl/OpenGLHelper.hxx>
15 #include "opengl/framebuffer.hxx"
16 #include "opengl/texture.hxx"
18 #include "opengl/PackedTextureAtlas.hxx"
20 struct Node
22 Rectangle mRectangle;
23 std::unique_ptr<Node> mLeftNode;
24 std::unique_ptr<Node> mRightNode;
25 bool mOccupied;
27 explicit Node(int nWidth, int nHeight);
28 explicit Node(Rectangle& aRectangle);
30 bool isLeaf();
31 Node* insert(int nWidth, int nHeight, int nPadding);
34 Node::Node(int nWidth, int nHeight)
35 : mRectangle(Rectangle(Point(), Size(nWidth, nHeight)))
36 , mLeftNode()
37 , mRightNode()
38 , mOccupied(false)
41 Node::Node(Rectangle& aRectangle)
42 : mRectangle(aRectangle)
43 , mLeftNode()
44 , mRightNode()
45 , mOccupied(false)
48 bool Node::isLeaf()
50 return mLeftNode.get() == nullptr &&
51 mRightNode.get() == nullptr;
54 Node* Node::insert(int nWidth, int nHeight, int nPadding)
56 if (!isLeaf())
58 Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding);
60 if (pNewNode != nullptr)
61 return pNewNode;
63 return mRightNode->insert(nWidth, nHeight, nPadding);
65 else
67 if (mOccupied)
69 return nullptr;
72 if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight())
73 { // does not fit
74 return nullptr;
77 if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight())
78 { // perfect fit
79 mOccupied = true;
80 return this;
83 int dw = mRectangle.GetWidth() - nWidth;
84 int dh = mRectangle.GetHeight() - nHeight;
86 Rectangle aLeftRect;
87 Rectangle aRightRect;
88 if (dw > dh)
90 aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
91 Size(nWidth, mRectangle.GetHeight()));
92 aRightRect = Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
93 Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
95 else
97 aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
98 Size(mRectangle.GetWidth(), nHeight));
99 aRightRect = Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight),
100 Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding));
103 mLeftNode.reset(new Node(aLeftRect));
104 mRightNode.reset(new Node(aRightRect));
106 return mLeftNode->insert(nWidth, nHeight, nPadding);
110 struct PackedTexture
112 std::unique_ptr<ImplOpenGLTexture> mpTexture;
113 std::unique_ptr<Node> mpRootNode;
114 int mnDeallocatedArea;
116 PackedTexture(int nWidth, int nHeight)
117 : mpTexture(new ImplOpenGLTexture(nWidth, nHeight, true))
118 , mpRootNode(new Node(nWidth, nHeight))
119 , mnDeallocatedArea(0)
123 PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight)
124 : mnTextureWidth(nTextureWidth)
125 , mnTextureHeight(nTextureHeight)
129 PackedTextureAtlasManager::~PackedTextureAtlasManager()
131 for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
133 // Free texture early in VCL shutdown while we have a context.
134 pPackedTexture->mpTexture.reset();
138 void PackedTextureAtlasManager::CreateNewTexture()
140 std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture(mnTextureWidth, mnTextureHeight));
141 GLuint nTextureID = pPackedTexture->mpTexture->mnTexture;
142 maPackedTextures.push_back(std::move(pPackedTexture));
143 VCL_GL_INFO("PackedTextureAtlas::CreateNewTexture adding texture: " << nTextureID <<
144 " atlases: " << maPackedTextures.size());
147 OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight)
149 for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
151 Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
152 if (pNode != nullptr)
154 return OpenGLTexture(pPackedTexture->mpTexture.get(), pNode->mRectangle, -1);
157 CreateNewTexture();
158 std::unique_ptr<PackedTexture>& pPackedTexture = maPackedTextures.back();
159 Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
160 if (pNode != nullptr)
162 return OpenGLTexture(pPackedTexture->mpTexture.get(), pNode->mRectangle, -1);
164 return OpenGLTexture();
167 OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
169 OpenGLTexture aTexture = Reserve(nWidth, nHeight);
170 if (aTexture && pData == nullptr)
171 return aTexture;
173 aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
175 return aTexture;
178 std::vector<GLuint> PackedTextureAtlasManager::ReduceTextureNumber(int nMaxNumberOfTextures)
180 std::vector<GLuint> aTextureIDs;
181 while (int(maPackedTextures.size()) > nMaxNumberOfTextures)
183 // Remove oldest created texture
184 GLuint nTextureID = maPackedTextures[0]->mpTexture->mnTexture;
185 aTextureIDs.push_back(nTextureID);
186 maPackedTextures.erase(maPackedTextures.begin());
187 VCL_GL_INFO("PackedTextureAtlas::ReduceTextureNumber removing texture: " << nTextureID <<
188 " atlases: " << maPackedTextures.size());
190 return aTextureIDs;
193 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */