TexturePacker now tries to create the smallest texture atlas as possible.

--HG--
branch : dev
This commit is contained in:
Martín Lucas Golini
2017-08-06 04:18:00 -03:00
parent 0481f869d2
commit f69f75a552
9 changed files with 100 additions and 38 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 189 KiB

View File

@@ -6,6 +6,7 @@
#include <eepp/math/size.hpp>
#include <eepp/math/rect.hpp>
#include <eepp/math/vector2.hpp>
#include <eepp/core/string.hpp>
using namespace EE::Math;
@@ -37,6 +38,20 @@ class EE_API PixelDensity {
return toFloat( (EE_PIXEL_DENSITY)pd );
}
static EE_PIXEL_DENSITY fromString( std::string str ) {
String::toLowerInPlace( str );
if ( "mdpi" == str ) return PD_MDPI;
else if ( "hdpi" == str ) return PD_HDPI;
else if ( "xhdpi" == str ) return PD_XHDPI;
else if ( "xxhdpi" == str ) return PD_XXHDPI;
else if ( "xxxhdpi" == str ) return PD_XXXHDPI;
return PD_MDPI;
}
static EE_PIXEL_DENSITY fromString( String str ) {
return fromString( str.toUtf8() );
}
static const Float& getPixelDensity();
static void setPixelDensity( const Float& pixelDensity );

View File

@@ -113,11 +113,11 @@ class EE_API TexturePacker {
std::list<TexturePackerTex*> mTextures;
Int32 mLongestEdge;
Int32 mTotalArea;
TexturePackerNode * mFreeList;
Int32 mWidth;
Int32 mHeight;
Sizei mMaxSize;
bool mPacked;
bool mAllowFlipping;
TexturePacker * mChild;
@@ -169,6 +169,8 @@ class EE_API TexturePacker {
void createChild();
bool addPackerTex( TexturePackerTex * TPack );
void reset();
};
}}

View File

@@ -9,11 +9,10 @@
namespace EE { namespace Graphics {
TexturePacker::TexturePacker( const Uint32& MaxWidth, const Uint32& MaxHeight, const EE_PIXEL_DENSITY& PixelDensity, const bool& ForcePowOfTwo, const Uint32& PixelBorder, const bool& AllowFlipping ) :
mLongestEdge(0),
mTotalArea(0),
mFreeList(NULL),
mWidth(0),
mHeight(0),
mWidth(128),
mHeight(128),
mPacked(false),
mAllowFlipping(false),
mChild(NULL),
@@ -28,11 +27,11 @@ TexturePacker::TexturePacker( const Uint32& MaxWidth, const Uint32& MaxHeight, c
}
TexturePacker::TexturePacker() :
mLongestEdge(0),
mTotalArea(0),
mFreeList(NULL),
mWidth(1024),
mHeight(1024),
mWidth(128),
mHeight(128),
mMaxSize(mWidth, mHeight),
mPacked(false),
mAllowFlipping(false),
mChild(NULL),
@@ -51,8 +50,7 @@ TexturePacker::~TexturePacker()
}
void TexturePacker::close() {
mLongestEdge = 0;
mTotalArea = 0;
reset();
std::list<TexturePackerTex*>::iterator it;
@@ -61,6 +59,19 @@ void TexturePacker::close() {
}
mTextures.clear();
}
void TexturePacker::reset() {
mStrategy = PackBig;
mCount = mTextures.size();
TexturePackerTex * t = NULL;
std::list<TexturePackerTex*>::iterator it;
for ( it = mTextures.begin(); it != mTextures.end(); it++ ) {
t = (*it);
t->placed( false );
}
if ( NULL != mFreeList ) {
TexturePackerNode * next = mFreeList;
@@ -73,6 +84,8 @@ void TexturePacker::close() {
eeSAFE_DELETE( kill );
}
mFreeList = NULL;
}
eeSAFE_DELETE( mChild );
@@ -80,14 +93,14 @@ void TexturePacker::close() {
void TexturePacker::setOptions( const Uint32& MaxWidth, const Uint32& MaxHeight, const EE_PIXEL_DENSITY& PixelDensity, const bool& ForcePowOfTwo, const Uint32& PixelBorder, const bool& AllowFlipping ) {
if ( !mTextures.size() ) { // only can change the dimensions before adding any texture
mWidth = MaxWidth;
mHeight = MaxHeight;
mMaxSize.x = MaxWidth;
mMaxSize.y = MaxHeight;
if ( ForcePowOfTwo && !Math::isPow2( mWidth ) )
mWidth = Math::nextPowOfTwo( mWidth );
if ( ForcePowOfTwo && !Math::isPow2( mMaxSize.x ) )
mMaxSize.x = Math::nextPowOfTwo( mMaxSize.x );
if ( ForcePowOfTwo && !Math::isPow2( mHeight ) )
mHeight = Math::nextPowOfTwo( mHeight );
if ( ForcePowOfTwo && !Math::isPow2( mMaxSize.y ) )
mMaxSize.y = Math::nextPowOfTwo( mMaxSize.y );
mForcePowOfTwo = ForcePowOfTwo;
mAllowFlipping = AllowFlipping;
@@ -192,8 +205,6 @@ void TexturePacker::addBorderToTextures( const Int32& BorderSize ) {
t->width ( t->width() + BorderSize );
t->height ( t->height() + BorderSize );
}
mLongestEdge += BorderSize;
}
}
@@ -376,10 +387,9 @@ void TexturePacker::createChild() {
bool TexturePacker::addTexturesPath( std::string TexturesPath ) {
if ( FileSystem::isDirectory( TexturesPath ) ) {
FileSystem::dirPathAddSlashAtEnd( TexturesPath );
std::vector<std::string > files = FileSystem::filesGetInPath( TexturesPath );
std::vector<std::string> files = FileSystem::filesGetInPath( TexturesPath );
std::sort( files.begin(), files.end() );
for ( Uint32 i = 0; i < files.size(); i++ ) {
@@ -397,8 +407,8 @@ bool TexturePacker::addTexturesPath( std::string TexturesPath ) {
bool TexturePacker::addPackerTex( TexturePackerTex * TPack ) {
if ( TPack->loadedInfo() ) {
// Only add the texture if can fit inside the atlas, otherwise it will ignore it
if ( ( TPack->width() + mPixelBorder <= mWidth && TPack->height() + mPixelBorder <= mHeight ) ||
( mAllowFlipping && ( TPack->width() + mPixelBorder <= mHeight && TPack->height() + mPixelBorder <= mWidth ) )
if ( ( TPack->width() + mPixelBorder <= mMaxSize.getWidth() && TPack->height() + mPixelBorder <= mMaxSize.getHeight() ) ||
( mAllowFlipping && ( TPack->width() + mPixelBorder <= mMaxSize.getHeight() && TPack->height() + mPixelBorder <= mMaxSize.getWidth() ) )
)
{
mTotalArea += TPack->area();
@@ -442,9 +452,6 @@ bool TexturePacker::addTexture( const std::string& TexturePath ) {
}
Int32 TexturePacker::packTextures() { // pack the textures, the return code is the amount of wasted/unused area.
if ( mWidth <= 0 || mHeight <= 0 )
return 0;
TexturePackerTex * t = NULL;
addBorderToTextures( (Int32)mPixelBorder );
@@ -476,7 +483,7 @@ Int32 TexturePacker::packTextures() { // pack the textures, the return code is t
eePRINTL( "Chaging Strategy to Tiny. %s faults.", t->name().c_str() );
} else if ( PackTiny == mStrategy ) {
mStrategy = PackFail;
eePRINTL( "Strategy fail, must create a new image. %s faults.", t->name().c_str() );
eePRINTL( "Strategy fail, must expand image or create a new one. %s faults.", t->name().c_str() );
}
} else {
insertTexture( t, bestFit, edgeCount, previousBestFit );
@@ -484,8 +491,28 @@ Int32 TexturePacker::packTextures() { // pack the textures, the return code is t
}
if ( PackFail == mStrategy ) {
eePRINTL( "Creating a new image as a child." );
createChild();
if ( mWidth < mMaxSize.getWidth() || mHeight < mMaxSize.getHeight() ) {
reset();
addBorderToTextures( -( (Int32)mPixelBorder ) );
if ( mWidth <= mHeight ) {
mWidth *= 2;
if ( mWidth > mMaxSize.getWidth() )
mWidth = mMaxSize.getWidth();
} else {
mHeight *= 2;
if ( mHeight > mMaxSize.getHeight() )
mHeight = mMaxSize.getHeight();
}
return packTextures();
} else {
eePRINTL( "Creating a new image as a child." );
createChild();
}
break;
}
}

View File

@@ -43,6 +43,8 @@ class TexturePackerTex {
inline const bool& placed() const { return mPlaced; }
inline void placed( bool placed ) { mPlaced = placed; }
inline const bool& flipped() const { return mFlipped; }
inline const Int32& longestEdge() const { return mLongestEdge; }

View File

@@ -17,7 +17,7 @@ TextureAtlasNew::TextureAtlasNew( TGCreateCb NewTGCb ) :
return;
mUIWindow = UIWindow::New();
mUIWindow->setSizeWithDecoration( 378, 244 )->setWinFlags( UI_WIN_CLOSE_BUTTON | UI_WIN_USE_DEFAULT_BUTTONS_ACTIONS | UI_WIN_SHARE_ALPHA_WITH_CHILDS | UI_WIN_MODAL )->setMinWindowSize( 378, 244 );
mUIWindow->setSizeWithDecoration( 378, 244 )->setWinFlags( UI_WIN_CLOSE_BUTTON | UI_WIN_USE_DEFAULT_BUTTONS_ACTIONS | UI_WIN_SHARE_ALPHA_WITH_CHILDS | UI_WIN_MODAL )->setMinWindowSize( 378, 260 );
mUIWindow->addEventListener( UIEvent::EventOnWindowClose, cb::Make1( this, &TextureAtlasNew::windowClose ) );
mUIWindow->setTitle( "New Texture Atlas" );
@@ -33,6 +33,7 @@ TextureAtlasNew::TextureAtlasNew( TGCreateCb NewTGCb ) :
FileTypes.push_back( "BMP" );
FileTypes.push_back( "PNG" );
FileTypes.push_back( "DDS" );
FileTypes.push_back( "JPG" );
mSaveFileType->getListBox()->addListBoxItems( FileTypes );
mSaveFileType->getListBox()->setSelected( "PNG" );
@@ -57,7 +58,7 @@ TextureAtlasNew::TextureAtlasNew( TGCreateCb NewTGCb ) :
std::vector<String> Sizes;
for ( Uint32 i = 6; i < 14; i++ ) {
for ( Uint32 i = 8; i < 15; i++ ) {
Sizes.push_back( String::toStr( 1 << i ) );
}
@@ -65,20 +66,34 @@ TextureAtlasNew::TextureAtlasNew( TGCreateCb NewTGCb ) :
mComboHeight->getListBox()->addListBoxItems( Sizes );
mComboWidth->getInputTextBuffer()->setAllowOnlyNumbers( true );
mComboHeight->getInputTextBuffer()->setAllowOnlyNumbers( true );
mComboWidth->getListBox()->setSelected( "512" );
mComboHeight->getListBox()->setSelected( "512" );
mComboWidth->getListBox()->setSelected( "2048" );
mComboHeight->getListBox()->setSelected( "2048" );
createTxtBox( Vector2i( 10, 110 ), "Space between sub textures (pixels):" );
mPixelSpace = UISpinBox::New();
mPixelSpace->setParent( mUIWindow->getContainer() )->setSize( 100, 0 )->setPosition( PosX, 110 )->setVisible( true )->setEnabled( true );
createTxtBox( Vector2i( 10, 140 ), "Texture Atlas Folder Path:" );
createTxtBox( Vector2i( 10, 140 ), "Pixel Density:" );
mPixelDensity = UIDropDownList::New();
mPixelDensity->setParent( mUIWindow->getContainer() )->setSize( 100, 0 )->setPosition( PosX, 140 );
std::vector<String> PixelDensities;
PixelDensities.push_back( "MDPI" );
PixelDensities.push_back( "HDPI" );
PixelDensities.push_back( "XHDPI" );
PixelDensities.push_back( "XXHDPI" );
PixelDensities.push_back( "XXXHDPI" );
mPixelDensity->getListBox()->addListBoxItems( PixelDensities );
mPixelDensity->getListBox()->setSelected( "MDPI" );
createTxtBox( Vector2i( 10, 170 ), "Texture Atlas Folder Path:" );
mTGPath = UITextInput::New()->setMaxLength( 512 );
mTGPath->setParent( mUIWindow->getContainer() )->setSize( mUIWindow->getContainer()->getSize().getWidth() - 60, 0 )->setPosition( 10, 160 );
mTGPath->setParent( mUIWindow->getContainer() )->setSize( mUIWindow->getContainer()->getSize().getWidth() - 60, 0 )->setPosition( 10, 190 );
mTGPath->setAllowEditing( false );
mSetPathButton = UIPushButton::New();
mSetPathButton->setParent( mUIWindow->getContainer() )->setSize( 32, 22 )->setPosition( mUIWindow->getContainer()->getSize().getWidth() - 10 - 32, 160 );
mSetPathButton->setParent( mUIWindow->getContainer() )->setSize( 32, mTGPath->getSize().getHeight() )->setPosition( mUIWindow->getContainer()->getSize().getWidth() - 10 - 32, 190 );
mSetPathButton->setText( "..." );
mSetPathButton->addEventListener( UIEvent::EventMouseClick, cb::Make1( this, &TextureAtlasNew::onDialogFolderSelect ) );
@@ -143,7 +158,7 @@ void TextureAtlasNew::windowClose( const UIEvent * Event ) {
}
static bool isValidExtension( const std::string& ext ) {
return ext == "png" || ext == "bmp" || ext == "dds" || ext == "tga";
return ext == "png" || ext == "bmp" || ext == "dds" || ext == "tga" || ext == "jpg";
}
void TextureAtlasNew::textureAtlasSave( const UIEvent * Event ) {
@@ -157,7 +172,7 @@ void TextureAtlasNew::textureAtlasSave( const UIEvent * Event ) {
b = static_cast<Int32>( mPixelSpace->getValue() );
if ( Res1 && Res2 ) {
Graphics::TexturePacker * TexturePacker = eeNew( Graphics::TexturePacker, ( w, h, PD_MDPI, false, b ) );
Graphics::TexturePacker * TexturePacker = eeNew( Graphics::TexturePacker, ( w, h, PixelDensity::fromString( mPixelDensity->getText() ), false, b ) );
TexturePacker->addTexturesPath( mTGPath->getText() );

View File

@@ -23,10 +23,11 @@ class EE_API TextureAtlasNew {
TGCreateCb mNewTGCb;
UIComboBox * mComboWidth;
UIComboBox * mComboHeight;
UISpinBox * mPixelSpace;
UISpinBox * mPixelSpace;
UITextInput * mTGPath;
UIPushButton * mSetPathButton;
UIDropDownList * mSaveFileType;
UIDropDownList * mPixelDensity;
void windowClose( const UIEvent * Event );

View File

@@ -1046,7 +1046,7 @@ void EETest::onTextureLoaded( ResourceLoader * ResLoaded ) {
void EETest::loadTextures() {
if ( !FileSystem::fileExists( MyPath + "atlases/bnb.eta" ) ) {
TexturePacker tp( 512, 512, PD_MDPI, true, 0 );
TexturePacker tp( 1024, 512, PD_MDPI, true, 1 );
tp.addTexturesPath( MyPath + "atlases/bnb/" );
tp.save( MyPath + "atlases/bnb.png" );
}