ccb2a1f650
redundant get() call on smart pointer Change-Id: Icb5a03bbc15e79a30d3d135a507d22914d15c2bd Reviewed-on: https://gerrit.libreoffice.org/61837 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
188 lines
5.8 KiB
C++
188 lines
5.8 KiB
C++
/* -*- 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 <memory>
|
|
#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
|
|
{
|
|
tools::Rectangle const mRectangle;
|
|
std::unique_ptr<Node> mLeftNode;
|
|
std::unique_ptr<Node> mRightNode;
|
|
bool mOccupied;
|
|
|
|
explicit Node(int nWidth, int nHeight);
|
|
explicit Node(tools::Rectangle const & aRectangle);
|
|
|
|
bool isLeaf();
|
|
Node* insert(int nWidth, int nHeight, int nPadding);
|
|
};
|
|
|
|
Node::Node(int nWidth, int nHeight)
|
|
: mRectangle(tools::Rectangle(Point(), Size(nWidth, nHeight)))
|
|
, mLeftNode()
|
|
, mRightNode()
|
|
, mOccupied(false)
|
|
{}
|
|
|
|
Node::Node(tools::Rectangle const & aRectangle)
|
|
: mRectangle(aRectangle)
|
|
, mLeftNode()
|
|
, mRightNode()
|
|
, mOccupied(false)
|
|
{}
|
|
|
|
bool Node::isLeaf() { return mLeftNode == nullptr && mRightNode == 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;
|
|
|
|
tools::Rectangle aLeftRect;
|
|
tools::Rectangle aRightRect;
|
|
if (dw > dh)
|
|
{
|
|
aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
|
|
Size(nWidth, mRectangle.GetHeight()));
|
|
aRightRect = tools::Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
|
|
Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
|
|
}
|
|
else
|
|
{
|
|
aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
|
|
Size(mRectangle.GetWidth(), nHeight));
|
|
aRightRect = tools::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::shared_ptr<ImplOpenGLTexture> mpTexture;
|
|
std::unique_ptr<Node> mpRootNode;
|
|
|
|
PackedTexture(int nWidth, int nHeight)
|
|
: mpTexture(new ImplOpenGLTexture(nWidth, nHeight, true))
|
|
, mpRootNode(new Node(nWidth, nHeight))
|
|
{}
|
|
};
|
|
|
|
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.reset();
|
|
}
|
|
}
|
|
|
|
void PackedTextureAtlasManager::CreateNewTexture()
|
|
{
|
|
std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture(mnTextureWidth, mnTextureHeight));
|
|
GLuint nTextureID = pPackedTexture->mpTexture->mnTexture;
|
|
maPackedTextures.push_back(std::move(pPackedTexture));
|
|
VCL_GL_INFO("PackedTextureAtlas::CreateNewTexture adding texture: " << nTextureID <<
|
|
" atlases: " << maPackedTextures.size());
|
|
}
|
|
|
|
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 const * pData)
|
|
{
|
|
OpenGLTexture aTexture = Reserve(nWidth, nHeight);
|
|
if (aTexture && pData == nullptr)
|
|
return aTexture;
|
|
|
|
aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
|
|
|
|
return aTexture;
|
|
}
|
|
|
|
std::vector<GLuint> PackedTextureAtlasManager::ReduceTextureNumber(int nMaxNumberOfTextures)
|
|
{
|
|
std::vector<GLuint> aTextureIDs;
|
|
while (int(maPackedTextures.size()) > nMaxNumberOfTextures)
|
|
{
|
|
// Remove oldest created texture
|
|
GLuint nTextureID = maPackedTextures[0]->mpTexture->mnTexture;
|
|
aTextureIDs.push_back(nTextureID);
|
|
maPackedTextures.erase(maPackedTextures.begin());
|
|
VCL_GL_INFO("PackedTextureAtlas::ReduceTextureNumber removing texture: " << nTextureID <<
|
|
" atlases: " << maPackedTextures.size());
|
|
}
|
|
return aTextureIDs;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|