mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-11 01:01:25 +03:00
TexturePacker now tries to create the smallest texture atlas as possible.
--HG-- branch : dev
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 189 KiB |
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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() );
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user