Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / vcl / opengl / PackedTextureAtlas.cxx
blob8508bbe3ca18e72ca77819ae687379c4a5b5fbf5
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 <memory>
12 #include <sal/config.h>
13 #include <vcl/opengl/OpenGLContext.hxx>
14 #include <vcl/opengl/OpenGLHelper.hxx>
16 #include <opengl/framebuffer.hxx>
17 #include <opengl/texture.hxx>
19 #include <opengl/PackedTextureAtlas.hxx>
21 namespace {
23 struct Node
25 tools::Rectangle mRectangle;
26 std::unique_ptr<Node> mLeftNode;
27 std::unique_ptr<Node> mRightNode;
28 bool mOccupied;
30 explicit Node(int nWidth, int nHeight);
31 explicit Node(tools::Rectangle const & aRectangle);
33 bool isLeaf() const;
34 Node* insert(int nWidth, int nHeight, int nPadding);
39 Node::Node(int nWidth, int nHeight)
40 : mRectangle(tools::Rectangle(Point(), Size(nWidth, nHeight)))
41 , mLeftNode()
42 , mRightNode()
43 , mOccupied(false)
46 Node::Node(tools::Rectangle const & aRectangle)
47 : mRectangle(aRectangle)
48 , mLeftNode()
49 , mRightNode()
50 , mOccupied(false)
53 bool Node::isLeaf() const { return mLeftNode == nullptr && mRightNode == nullptr; }
55 Node* Node::insert(int nWidth, int nHeight, int nPadding)
57 if (!isLeaf())
59 Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding);
61 if (pNewNode != nullptr)
62 return pNewNode;
64 return mRightNode->insert(nWidth, nHeight, nPadding);
66 else
68 if (mOccupied)
70 return nullptr;
73 if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight())
74 { // does not fit
75 return nullptr;
78 if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight())
79 { // perfect fit
80 mOccupied = true;
81 return this;
84 int dw = mRectangle.GetWidth() - nWidth;
85 int dh = mRectangle.GetHeight() - nHeight;
87 tools::Rectangle aLeftRect;
88 tools::Rectangle aRightRect;
89 if (dw > dh)
91 aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
92 Size(nWidth, mRectangle.GetHeight()));
93 aRightRect = tools::Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
94 Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
96 else
98 aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
99 Size(mRectangle.GetWidth(), nHeight));
100 aRightRect = tools::Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight),
101 Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding));
104 mLeftNode.reset(new Node(aLeftRect));
105 mRightNode.reset(new Node(aRightRect));
107 return mLeftNode->insert(nWidth, nHeight, nPadding);
111 struct PackedTexture
113 std::shared_ptr<ImplOpenGLTexture> mpTexture;
114 std::unique_ptr<Node> mpRootNode;
116 PackedTexture(int nWidth, int nHeight)
117 : mpTexture(std::make_shared<ImplOpenGLTexture>(nWidth, nHeight, true))
118 , mpRootNode(new Node(nWidth, nHeight))
122 PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight)
123 : mnTextureWidth(nTextureWidth)
124 , mnTextureHeight(nTextureHeight)
128 PackedTextureAtlasManager::~PackedTextureAtlasManager()
130 for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
132 // Free texture early in VCL shutdown while we have a context.
133 pPackedTexture->mpTexture.reset();
137 void PackedTextureAtlasManager::CreateNewTexture()
139 std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture(mnTextureWidth, mnTextureHeight));
140 GLuint nTextureID = pPackedTexture->mpTexture->mnTexture;
141 maPackedTextures.push_back(std::move(pPackedTexture));
142 VCL_GL_INFO("PackedTextureAtlas::CreateNewTexture adding texture: " << nTextureID <<
143 " atlases: " << maPackedTextures.size());
146 OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight)
148 for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
150 Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
151 if (pNode != nullptr)
153 return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
156 CreateNewTexture();
157 std::unique_ptr<PackedTexture>& pPackedTexture = maPackedTextures.back();
158 Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
159 if (pNode != nullptr)
161 return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
163 return OpenGLTexture();
166 OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData)
168 OpenGLTexture aTexture = Reserve(nWidth, nHeight);
169 if (aTexture && pData == nullptr)
170 return aTexture;
172 aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
174 return aTexture;
177 std::vector<GLuint> PackedTextureAtlasManager::ReduceTextureNumber(int nMaxNumberOfTextures)
179 std::vector<GLuint> aTextureIDs;
180 while (int(maPackedTextures.size()) > nMaxNumberOfTextures)
182 // Remove oldest created texture
183 GLuint nTextureID = maPackedTextures[0]->mpTexture->mnTexture;
184 aTextureIDs.push_back(nTextureID);
185 maPackedTextures.erase(maPackedTextures.begin());
186 VCL_GL_INFO("PackedTextureAtlas::ReduceTextureNumber removing texture: " << nTextureID <<
187 " atlases: " << maPackedTextures.size());
189 return aTextureIDs;
192 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */