You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/Common/Textures/PowerOf2BlockPacker.cpp

232 lines
5.3 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "PowerOf2BlockPacker.h"
CPowerOf2BlockPacker::CPowerOf2BlockPacker(const uint32 dwLogWidth, const uint32 dwLogHeight)
{
m_dwWidth = 1 << dwLogWidth;
m_dwHeight = 1 << dwLogHeight;
m_nUsedBlocks = 0;
m_pTexture = NULL;
m_BlockBitmap.resize(m_dwWidth * m_dwHeight, 0xffffffff);
}
CPowerOf2BlockPacker::~CPowerOf2BlockPacker()
{
//Clear();
FreeContainers();
SAFE_RELEASE(m_pTexture);
}
void CPowerOf2BlockPacker::Clear()
{
std::fill(m_BlockBitmap.begin(), m_BlockBitmap.end(), 0xffffffff);
m_Blocks.clear();
m_nUsedBlocks = 0;
}
uint32 CPowerOf2BlockPacker::GetBlockInfo(const uint32 dwBlockID, uint32& dwMinX, uint32& dwMinY, uint32& dwMaxX, uint32& dwMaxY)
{
uint32 dwSize = (uint32)m_Blocks.size();
if (dwBlockID >= dwSize)
{
return 0xFFFFFFFF; // to avoid crash
}
SBlockMinMax& ref = m_Blocks[dwBlockID];
dwMinX = ref.m_dwMinX;
dwMinY = ref.m_dwMinY;
dwMaxX = ref.m_dwMaxX;
dwMaxY = ref.m_dwMaxY;
if (ref.IsFree())
{
return 0xFFFFFFFF;
}
else
{
return dwBlockID;
}
}
void CPowerOf2BlockPacker::UpdateSize(int nW, int nH)
{
assert(m_nUsedBlocks == 0);
m_dwWidth = nW;
m_dwHeight = nH;
m_nUsedBlocks = 0;
m_BlockBitmap.resize(m_dwWidth * m_dwHeight, 0xffffffff);
}
void CPowerOf2BlockPacker::RemoveBlock(const uint32 dwBlockID)
{
uint32 dwSize = (uint32)m_Blocks.size();
assert(dwBlockID < dwSize);
if (dwBlockID >= dwSize)
{
return; // to avoid crash
}
SBlockMinMax& ref = m_Blocks[dwBlockID];
assert(!ref.IsFree());
FillRect(ref, 0xffffffff);
m_nUsedBlocks -= (ref.m_dwMaxX - ref.m_dwMinX) * (ref.m_dwMaxY - ref.m_dwMinY);
ref.MarkFree();
}
uint32 CPowerOf2BlockPacker::AddBlock(const uint32 dwLogWidth, const uint32 dwLogHeight)
{
uint32 dwLocalWidth = 1 << dwLogWidth;
uint32 dwLocalHeight = 1 << dwLogHeight;
for (uint32 dwY = 0; dwY < m_dwHeight; dwY += dwLocalHeight)
{
for (uint32 dwX = 0; dwX < m_dwWidth; dwX += dwLocalWidth)
{
SBlockMinMax testblock;
testblock.m_dwMinX = dwX;
testblock.m_dwMaxX = dwX + dwLocalWidth;
testblock.m_dwMinY = dwY;
testblock.m_dwMaxY = dwY + dwLocalHeight;
if (IsFree(testblock))
{
uint32 dwBlockID = FindFreeBlockIDOrCreateNew();
m_Blocks[dwBlockID] = testblock;
FillRect(testblock, dwBlockID);
m_nUsedBlocks += dwLocalWidth * dwLocalHeight;
return dwBlockID;
}
}
}
return 0xffffffff; // no space left to this block
}
void CPowerOf2BlockPacker::FillRect(const SBlockMinMax& rect, uint32 dwValue)
{
for (uint32 dwY = rect.m_dwMinY; dwY < rect.m_dwMaxY; ++dwY)
{
for (uint32 dwX = rect.m_dwMinX; dwX < rect.m_dwMaxX; ++dwX)
{
m_BlockBitmap[dwX + dwY * m_dwWidth] = dwValue;
}
}
}
bool CPowerOf2BlockPacker::IsFree(const SBlockMinMax& rect)
{
for (uint32 dwY = rect.m_dwMinY; dwY < rect.m_dwMaxY; ++dwY)
{
for (uint32 dwX = rect.m_dwMinX; dwX < rect.m_dwMaxX; ++dwX)
{
if (m_BlockBitmap.size() <= dwX + dwY * m_dwWidth || m_BlockBitmap[dwX + dwY * m_dwWidth] != 0xffffffff)
{
return false;
}
}
}
return true;
}
uint32 CPowerOf2BlockPacker::GetRandomBlock() const
{
std::vector<SBlockMinMax>::const_iterator it, end = m_Blocks.end();
uint32 dwCnt = 0;
for (it = m_Blocks.begin(); it != end; ++it)
{
const SBlockMinMax& ref = *it;
if (!ref.IsFree())
{
dwCnt++;
}
}
if (dwCnt == 0)
{
return 0xffffffff;
}
uint32 dwI = 0;
uint32 dwRndI = 0;
uint32 dwRnd = cry_random(0U, dwCnt - 1);
for (it = m_Blocks.begin(); it != end; ++it, ++dwI)
{
const SBlockMinMax& ref = *it;
if (!ref.IsFree())
{
if (dwRndI == dwRnd)
{
return dwI;
}
++dwRndI;
}
}
assert(0);
return 0xffffffff;
}
uint32 CPowerOf2BlockPacker::FindFreeBlockIDOrCreateNew()
{
std::vector<SBlockMinMax>::const_iterator it, end = m_Blocks.end();
uint32 dwI = 0;
for (it = m_Blocks.begin(); it != end; ++it, ++dwI)
{
const SBlockMinMax& ref = *it;
if (ref.IsFree())
{
return dwI;
}
}
m_Blocks.push_back(SBlockMinMax());
return (uint32)m_Blocks.size() - 1;
}
void CPowerOf2BlockPacker::FreeContainers()
{
Clear();
stl::free_container(m_Blocks);
stl::free_container(m_BlockBitmap);
}