From 28868341ec4f18df058dbbe9afe1f1abdd9249f1 Mon Sep 17 00:00:00 2001 From: spartanj Date: Fri, 20 Aug 2010 01:47:07 -0300 Subject: [PATCH] Added cTexturePacker. Utility class to create texture atlas and save the subtextures as shapes. Added cTextureGroupLoader. Utility class to load the texture atlas saved shapes ( sync and async ). Added cTexturePackerNode and cTexturePackerTex, both are helpers to create the texture atlas, and not visibles to the end user. Added some helpers functions for file path management. Added some new functions for cImage. scaling, resize, thumnails, copy image into image, and some others, and moved some cTexture functions to cImage. Added stbi_info support for BMP,PSD,HDR,PIC in stb_image. Added Progress() function to cResourceLoader, to know the current loading progress in percent ( 0%-100% ). Added api calls to some classes. But i'm still looking how to work with DLL. Modified some details in cTimer and cTimeElapsed. The code was only tested on linux, so, still need some checking, but, it's a lot of code, so i'll commit it and fix bugs if it's necessary. --- ee.linux.cbp | 9 + src/audio/caudiodevice.hpp | 2 +- src/audio/csoundfile.hpp | 2 +- src/audio/csoundfiledefault.hpp | 2 +- src/audio/csoundfileogg.hpp | 2 +- src/base.hpp | 2 - src/ee.h | 3 + src/graphics/cbatchrenderer.hpp | 2 +- src/graphics/cfontmanager.hpp | 2 +- src/graphics/cglobalbatchrenderer.hpp | 2 +- src/graphics/cimage.cpp | 168 ++++++- src/graphics/cimage.hpp | 33 +- src/graphics/cshape.hpp | 2 +- src/graphics/ctextcache.hpp | 2 +- src/graphics/ctexture.cpp | 49 +- src/graphics/ctexture.hpp | 20 +- src/graphics/ctexturegrouploader.cpp | 129 +++++ src/graphics/ctexturegrouploader.hpp | 50 ++ src/graphics/ctextureloader.cpp | 1 + src/graphics/ctexturepacker.cpp | 670 ++++++++++++++++++++++++++ src/graphics/ctexturepacker.hpp | 130 +++++ src/graphics/ctexturepackernode.cpp | 100 ++++ src/graphics/ctexturepackernode.hpp | 49 ++ src/graphics/ctexturepackertex.cpp | 38 ++ src/graphics/ctexturepackertex.hpp | 61 +++ src/graphics/packerhelper.hpp | 40 ++ src/helper/SOIL/stb_image.c | 355 ++++++++++++-- src/helper/SOIL/stb_image.h | 37 +- src/helper/SOIL/stbi_DDS_c.h | 10 +- src/helper/haikuttf/sophist.h | 61 +-- src/math/cmtrand.hpp | 2 +- src/math/math.hpp | 15 +- src/system/cobjectloader.hpp | 2 +- src/system/crc4.hpp | 2 +- src/system/cresourceloader.cpp | 4 + src/system/cresourceloader.hpp | 4 +- src/system/ctimeelapsed.cpp | 10 +- src/system/ctimeelapsed.hpp | 12 +- src/system/ctimer.cpp | 18 +- src/system/ctimer.hpp | 4 +- src/test/ee.cpp | 39 +- src/ui/cuibackground.hpp | 2 +- src/ui/cuiborder.hpp | 2 +- src/utils/cinterpolation.hpp | 2 +- src/utils/utils.cpp | 50 +- src/utils/utils.hpp | 14 +- 46 files changed, 2027 insertions(+), 188 deletions(-) create mode 100644 src/graphics/ctexturegrouploader.cpp create mode 100644 src/graphics/ctexturegrouploader.hpp create mode 100644 src/graphics/ctexturepacker.cpp create mode 100644 src/graphics/ctexturepacker.hpp create mode 100644 src/graphics/ctexturepackernode.cpp create mode 100644 src/graphics/ctexturepackernode.hpp create mode 100644 src/graphics/ctexturepackertex.cpp create mode 100644 src/graphics/ctexturepackertex.hpp create mode 100644 src/graphics/packerhelper.hpp diff --git a/ee.linux.cbp b/ee.linux.cbp index 706f500b7..a865d5a8b 100644 --- a/ee.linux.cbp +++ b/ee.linux.cbp @@ -120,13 +120,22 @@ + + + + + + + + + diff --git a/src/audio/caudiodevice.hpp b/src/audio/caudiodevice.hpp index 3ad5f0d1e..849a1fc28 100755 --- a/src/audio/caudiodevice.hpp +++ b/src/audio/caudiodevice.hpp @@ -5,7 +5,7 @@ namespace EE { namespace Audio { -class cAudioDevice { +class EE_API cAudioDevice { public : static cAudioDevice * instance(); diff --git a/src/audio/csoundfile.hpp b/src/audio/csoundfile.hpp index 8b99a2aad..1ab4e0141 100755 --- a/src/audio/csoundfile.hpp +++ b/src/audio/csoundfile.hpp @@ -5,7 +5,7 @@ namespace EE { namespace Audio { -class cSoundFile { +class EE_API cSoundFile { public: static cSoundFile* CreateRead(const std::string& Filename); static cSoundFile* CreateRead(const char* Data, std::size_t SizeInBytes); diff --git a/src/audio/csoundfiledefault.hpp b/src/audio/csoundfiledefault.hpp index c62ed3608..6af270bc2 100755 --- a/src/audio/csoundfiledefault.hpp +++ b/src/audio/csoundfiledefault.hpp @@ -9,7 +9,7 @@ namespace EE { namespace Audio { -class cSoundFileDefault : public cSoundFile { +class EE_API cSoundFileDefault : public cSoundFile { public : cSoundFileDefault(); ~cSoundFileDefault(); diff --git a/src/audio/csoundfileogg.hpp b/src/audio/csoundfileogg.hpp index b01fca769..5a5bc26a2 100755 --- a/src/audio/csoundfileogg.hpp +++ b/src/audio/csoundfileogg.hpp @@ -7,7 +7,7 @@ namespace EE { namespace Audio { -class cSoundFileOgg : public cSoundFile { +class EE_API cSoundFileOgg : public cSoundFile { public: cSoundFileOgg(); ~cSoundFileOgg(); diff --git a/src/base.hpp b/src/base.hpp index 23d53e194..21b410d7c 100644 --- a/src/base.hpp +++ b/src/base.hpp @@ -88,8 +88,6 @@ #endif namespace EE { - #define EE_CLOCKS_PER_SEC 1000000l - #define eeARRAY_SIZE(__array) ( sizeof(__array) / sizeof(__array[0]) ) #define eeSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define eeSAFE_FREE(p) { if(p) { free ( (void*)p );(p)=NULL; } } diff --git a/src/ee.h b/src/ee.h index 58ab61e89..c7ae5d8dc 100755 --- a/src/ee.h +++ b/src/ee.h @@ -91,9 +91,11 @@ // Graphics #include "graphics/renders.hpp" + #include "graphics/cimage.hpp" #include "graphics/ctexture.hpp" #include "graphics/ctextureloader.hpp" #include "graphics/ctexturefactory.hpp" + #include "graphics/ctexturepacker.hpp" #include "graphics/cshape.hpp" #include "graphics/cshapegroup.hpp" #include "graphics/cglobalshapegroup.hpp" @@ -117,6 +119,7 @@ #include "graphics/cshader.hpp" #include "graphics/cshaderprogram.hpp" #include "graphics/cshaderprogrammanager.hpp" + #include "graphics/ctexturegrouploader.hpp" using namespace EE::Graphics; // Gaming diff --git a/src/graphics/cbatchrenderer.hpp b/src/graphics/cbatchrenderer.hpp index eeb7950bb..97e57d8e9 100755 --- a/src/graphics/cbatchrenderer.hpp +++ b/src/graphics/cbatchrenderer.hpp @@ -18,7 +18,7 @@ typedef struct { } eeVertex; /** @brief A batch rendering class. */ -class cBatchRenderer { +class EE_API cBatchRenderer { public: cBatchRenderer(); ~cBatchRenderer(); diff --git a/src/graphics/cfontmanager.hpp b/src/graphics/cfontmanager.hpp index 0974cbc64..c39edef6c 100644 --- a/src/graphics/cfontmanager.hpp +++ b/src/graphics/cfontmanager.hpp @@ -6,7 +6,7 @@ namespace EE { namespace Graphics { -class cFontManager : public tResourceManager, public cSingleton { +class EE_API cFontManager : public tResourceManager, public cSingleton { friend class cSingleton; public: cFontManager(); diff --git a/src/graphics/cglobalbatchrenderer.hpp b/src/graphics/cglobalbatchrenderer.hpp index 7e9a13a45..a19237988 100755 --- a/src/graphics/cglobalbatchrenderer.hpp +++ b/src/graphics/cglobalbatchrenderer.hpp @@ -7,7 +7,7 @@ namespace EE { namespace Graphics { /** @brief The global Batch Renderer class. This class will be used by the engine for the rendering. */ -class cGlobalBatchRenderer : public cSingleton, public cBatchRenderer { +class EE_API cGlobalBatchRenderer : public cSingleton, public cBatchRenderer { friend class cSingleton; public: cGlobalBatchRenderer(); diff --git a/src/graphics/cimage.cpp b/src/graphics/cimage.cpp index 5194cfd46..e06c7abc8 100644 --- a/src/graphics/cimage.cpp +++ b/src/graphics/cimage.cpp @@ -1,4 +1,5 @@ #include "cimage.hpp" +#include "../helper/SOIL/image_helper.h" namespace EE { namespace Graphics { @@ -7,7 +8,8 @@ cImage::cImage() : mWidth(0), mHeight(0), mChannels(0), - mSize(0) + mSize(0), + mAvoidFree(false) { } @@ -16,7 +18,8 @@ cImage::cImage( const Uint8* data, const eeUint& Width, const eeUint& Height, co mWidth(Width), mHeight(Height), mChannels(Channels), - mSize(0) + mSize(0), + mAvoidFree(false) { SetPixels( data ); } @@ -26,13 +29,35 @@ cImage::cImage( const Uint32& Width, const Uint32& Height, const Uint32& Channel mWidth(Width), mHeight(Height), mChannels(Channels), - mSize(0) + mSize(0), + mAvoidFree(false) { Create( Width, Height, Channels ); } +cImage::cImage( Uint8* data, const eeUint& Width, const eeUint& Height, const eeUint& Channels ) : + mPixels( data ), + mWidth(Width), + mHeight(Height), + mChannels(Channels), + mSize(Width*Height*Channels), + mAvoidFree(false) +{ +} + cImage::~cImage() { - ClearCache(); + if ( !mAvoidFree ) + ClearCache(); +} + +void cImage::SetPixels( const Uint8* data ) { + if ( data != NULL ) { + eeUint size = (eeUint)mWidth * (eeUint)mHeight * mChannels; + + Allocate( size ); + + memcpy( reinterpret_cast( &mPixels[0] ), reinterpret_cast ( data ), size ); + } } const Uint8* cImage::GetPixelsPtr() { @@ -77,16 +102,6 @@ void cImage::Create( const Uint32& Width, const Uint32& Height, const Uint32& Ch Allocate( mWidth * mHeight * mChannels ); } -void cImage::SetPixels( const Uint8* data ) { - if ( data != NULL ) { - eeUint size = (eeUint)mWidth * (eeUint)mHeight * mChannels; - - Allocate( size ); - - memcpy( reinterpret_cast( &mPixels[0] ), reinterpret_cast ( data ), size ); - } -} - Uint8* cImage::GetPixels() const { return mPixels; } @@ -140,4 +155,129 @@ bool cImage::SaveToFile( const std::string& filepath, const EE_SAVETYPE& Format return Res; } +void cImage::ReplaceColor( const eeColorA& ColorKey, const eeColorA& NewColor ) { + eeUint Pos = 0; + + if ( NULL == mPixels ) + return; + + for ( eeUint i = 0; i < mWidth * mHeight; i++ ) { + Pos = i * mChannels; + + if ( 4 == mChannels ) { + if ( mPixels[ Pos ] == ColorKey.R() && mPixels[ Pos + 1 ] == ColorKey.G() && mPixels[ Pos + 2 ] == ColorKey.B() && mPixels[ Pos + 3 ] == ColorKey.A() ) { + mPixels[ Pos ] = NewColor.R(); + mPixels[ Pos + 1 ] = NewColor.G(); + mPixels[ Pos + 2 ] = NewColor.B(); + mPixels[ Pos + 3 ] = NewColor.A(); + } + } else if ( 3 == mChannels ) { + if ( mPixels[ Pos ] == ColorKey.R() && mPixels[ Pos + 1 ] == ColorKey.G() && mPixels[ Pos + 2 ] == ColorKey.B() ) { + mPixels[ Pos ] = NewColor.R(); + mPixels[ Pos + 1 ] = NewColor.G(); + mPixels[ Pos + 2 ] = NewColor.B(); + } + } else if ( 2 == mChannels ) { + if ( mPixels[ Pos ] == ColorKey.R() && mPixels[ Pos + 1 ] == ColorKey.G() ) { + mPixels[ Pos ] = NewColor.R(); + mPixels[ Pos + 1 ] = NewColor.G(); + } + } else if ( 1 == mChannels ) { + if ( mPixels[ Pos ] == ColorKey.R() ) { + mPixels[ Pos ] = NewColor.R(); + } + } + } +} + +void cImage::CreateMaskFromColor( const eeColorA& ColorKey, Uint8 Alpha ) { + ReplaceColor( ColorKey, eeColorA( ColorKey.R(), ColorKey.G(), ColorKey.B(), Alpha ) ); +} + +void cImage::CreateMaskFromColor( const eeColor& ColorKey, Uint8 Alpha ) { + CreateMaskFromColor( eeColorA( ColorKey.R(), ColorKey.G(), ColorKey.B(), 255 ), Alpha ); +} + +void cImage::FillWithColor( const eeColorA& Color ) { + if ( NULL == mPixels ) + return; + + eeUint z; + + for ( eeUint i = 0; i < mWidth * mHeight; i += mChannels ) { + for ( z = 0; z < mChannels; z++ ) { + if ( 0 == z ) + mPixels[ i + z ] = Color.R(); + else if ( 1 == z ) + mPixels[ i + z ] = Color.G(); + else if ( 2 == z ) + mPixels[ i + z ] = Color.B(); + else if ( 3 == z ) + mPixels[ i + z ] = Color.A(); + } + } +} + +void cImage::CopyImage( cImage * Img, const eeUint& x, const eeUint& y ) { + if ( NULL != mPixels && NULL != Img->GetPixels() && mWidth >= x + Img->Width() && mHeight >= y + Img->Height() ) { + eeUint dWidth = Img->Width(); + eeUint dHeight = Img->Height(); + + for ( eeUint ty = 0; ty < dHeight; ty++ ) { + for ( eeUint tx = 0; tx < dWidth; tx++ ) { + SetPixel( x + tx, y + ty, Img->GetPixel( tx, ty ) ); + } + } + } +} + +void cImage::Resize( const eeUint& new_width, const eeUint& new_height ) { + if ( NULL != mPixels && mWidth != new_width && mHeight != new_height ) { + unsigned char * resampled = new unsigned char[ mChannels * new_width * new_height ]; + + int res = up_scale_image( reinterpret_cast ( mPixels ), mWidth, mHeight, mChannels, resampled, new_width, new_height ); + + if ( res ) { + ClearCache(); + + mPixels = resampled; + mWidth = new_width; + mHeight = new_height; + } else + eeSAFE_DELETE_ARRAY( resampled ); + } +} + +void cImage::Scale( const eeFloat& scale ) { + if ( 1.f == scale ) + return; + + Int32 new_width = (Int32)( (eeFloat)mWidth * scale ); + Int32 new_height = (Int32)( (eeFloat)mHeight * scale ); + + Resize( new_width, new_height ); +} + +cImage * cImage::Thumbnail( const eeUint& max_width, const eeUint& max_height ) { + if ( NULL != mPixels && mWidth > max_width && mHeight > max_height ) { + eeFloat iScaleX = ( (eeFloat)max_width / (eeFloat)mWidth ); + eeFloat iScaleY = ( (eeFloat)max_height / (eeFloat)mHeight ); + eeFloat iScale = ( iScaleY < iScaleX ) ? iScaleY : iScaleX; + Int32 new_width = (Int32)( (eeFloat)mWidth * iScale ); + Int32 new_height = (Int32)( (eeFloat)mHeight * iScale ); + + unsigned char * resampled = new unsigned char[ mChannels * new_width * new_height ]; + + int res = up_scale_image( reinterpret_cast ( mPixels ), mWidth, mHeight, mChannels, resampled, new_width, new_height ); + + if ( res ) { + return new cImage( (Uint8*)resampled, new_width, new_height, mChannels ); + } else { + eeSAFE_DELETE_ARRAY( resampled ); + } + } + + return NULL; +} + }} diff --git a/src/graphics/cimage.hpp b/src/graphics/cimage.hpp index 24b449908..899b5d319 100644 --- a/src/graphics/cimage.hpp +++ b/src/graphics/cimage.hpp @@ -5,10 +5,13 @@ namespace EE { namespace Graphics { -class cImage { +class EE_API cImage { public: cImage(); + /** Use an existing image */ + cImage( Uint8* data, const eeUint& Width, const eeUint& Height, const eeUint& Channels ); + /** Copy a image data to create the image */ cImage( const Uint8* data, const eeUint& Width, const eeUint& Height, const eeUint& Channels ); @@ -61,12 +64,40 @@ class cImage { /** Save the Image to a new File in a specific format */ virtual bool SaveToFile( const std::string& filepath, const EE_SAVETYPE& Format ); + + /** Create an Alpha mask from a Color */ + virtual void CreateMaskFromColor( const eeColorA& ColorKey, Uint8 Alpha ); + + /** Create an Alpha mask from a Color */ + void CreateMaskFromColor( const eeColor& ColorKey, Uint8 Alpha ); + + /** Replace a color on the image */ + virtual void ReplaceColor( const eeColorA& ColorKey, const eeColorA& NewColor ); + + /** Fill the image with a color */ + virtual void FillWithColor( const eeColorA& Color ); + + /** Copy the image to this image data, starting from the position x,y */ + virtual void CopyImage( cImage * Img, const eeUint& x, const eeUint& y ); + + /** Scale the image */ + virtual void Scale( const eeFloat& scale ); + + /** Resize the image */ + virtual void Resize( const eeUint& new_width, const eeUint& new_height ); + + /** Create a thumnail of the image */ + cImage * Thumbnail( const eeUint& max_width, const eeUint& max_height ); + + /** Set as true if you dont want to free the image data ( false as default ). */ + void AvoidFreeImage( const bool& AvoidFree ) { mAvoidFree = AvoidFree; } protected: Uint8 * mPixels; eeUint mWidth; eeUint mHeight; eeUint mChannels; Uint32 mSize; + bool mAvoidFree; void Allocate( const Uint32& size ); }; diff --git a/src/graphics/cshape.hpp b/src/graphics/cshape.hpp index ec013d006..357496279 100644 --- a/src/graphics/cshape.hpp +++ b/src/graphics/cshape.hpp @@ -53,7 +53,7 @@ class EE_API cShape { void Draw( const eeFloat& X, const eeFloat& Y, const eeRGBA& Color = eeRGBA(), const eeFloat& Angle = 0.f, const eeFloat& Scale = 1.f, const EE_RENDERALPHAS& Blend = ALPHA_NORMAL, const EE_RENDERTYPE& Effect = RN_NORMAL, const bool& ScaleRendered = true ); - void Draw( const eeFloat& X, const eeFloat& Y, const eeFloat& Angle = 0.f, const eeFloat& Scale = 1.f, const eeRGBA& Color0 = eeRGBA(), const eeRGBA& Color1 = eeRGBA(), const eeRGBA& Color2 = eeRGBA(), const eeRGBA& Color3 = eeRGBA(), const EE_RENDERALPHAS& Blend = ALPHA_NORMAL, const EE_RENDERTYPE& Effect = RN_NORMAL, const bool& ScaleRendered = true ); + void Draw( const eeFloat& X, const eeFloat& Y, const eeFloat& Angle, const eeFloat& Scale, const eeRGBA& Color0 = eeRGBA(), const eeRGBA& Color1 = eeRGBA(), const eeRGBA& Color2 = eeRGBA(), const eeRGBA& Color3 = eeRGBA(), const EE_RENDERALPHAS& Blend = ALPHA_NORMAL, const EE_RENDERTYPE& Effect = RN_NORMAL, const bool& ScaleRendered = true ); cTexture * GetTexture(); diff --git a/src/graphics/ctextcache.hpp b/src/graphics/ctextcache.hpp index 553a1be6f..3e7a969b4 100644 --- a/src/graphics/ctextcache.hpp +++ b/src/graphics/ctextcache.hpp @@ -9,7 +9,7 @@ namespace EE { namespace Graphics { class cFont; /** @brief Cached text for a fast font rendering. */ -class cTextCache { +class EE_API cTextCache { public: cTextCache( cFont * font, const std::wstring& text = L"", eeColorA FontColor = eeColorA(0xFFFFFFFF), eeColorA ShadowColor = eeColorA(0xFF000000) ); diff --git a/src/graphics/ctexture.cpp b/src/graphics/ctexture.cpp index 0f2e812e8..0a16e5896 100755 --- a/src/graphics/ctexture.cpp +++ b/src/graphics/ctexture.cpp @@ -251,31 +251,44 @@ void cTexture::SetTextureFilter(const EE_TEX_FILTER& filter) { } } -void cTexture::ReplaceColor(eeColorA ColorKey, eeColorA NewColor) { +void cTexture::ReplaceColor( const eeColorA& ColorKey, const eeColorA& NewColor ) { + Lock(); + + cImage::ReplaceColor( ColorKey, NewColor ); + + Unlock( false, true ); +} + +void cTexture::CreateMaskFromColor( const eeColorA& ColorKey, Uint8 Alpha ) { Lock( true ); - eeUint Pos = 0; + cImage::ReplaceColor( ColorKey, eeColorA( ColorKey.R(), ColorKey.G(), ColorKey.B(), Alpha ) ); - for ( eeUint i = 0; i < mWidth * mHeight; i++ ) { - Pos = i * mChannels; - - if ( mPixels[ Pos ] == ColorKey.R() && mPixels[ Pos + 1 ] == ColorKey.G() && mPixels[ Pos + 2 ] == ColorKey.B() && mPixels[ Pos + 3 ] == ColorKey.A() ) { - mPixels[ Pos ] = NewColor.R(); - mPixels[ Pos + 1 ] = NewColor.G(); - mPixels[ Pos + 2 ] = NewColor.B(); - mPixels[ Pos + 3 ] = NewColor.A(); - } - } - - Unlock(false, true); + Unlock( false, true ); } -void cTexture::CreateMaskFromColor(eeColorA ColorKey, Uint8 Alpha) { - ReplaceColor( ColorKey, eeColorA( ColorKey.R(), ColorKey.G(), ColorKey.B(), Alpha ) ); +void cTexture::FillWithColor( const eeColorA& Color ) { + Lock(); + + cImage::FillWithColor( Color ); + + Unlock( false, true ); } -void cTexture::CreateMaskFromColor(eeColor ColorKey, Uint8 Alpha) { - CreateMaskFromColor( eeColorA( ColorKey.R(), ColorKey.G(), ColorKey.B(), 255 ), Alpha ); +void cTexture::Resize( const eeUint& new_width, const eeUint& new_height ) { + Lock(); + + cImage::Resize( new_width, new_height ); + + Unlock( false, true ); +} + +void cTexture::CopyImage( cImage * Img, const eeUint& x, const eeUint& y ) { + Lock(); + + cImage::CopyImage( Img, x, y ); + + Unlock( false, true ); } bool cTexture::LocalCopy() { diff --git a/src/graphics/ctexture.hpp b/src/graphics/ctexture.hpp index 1b708a932..a43933c10 100755 --- a/src/graphics/ctexture.hpp +++ b/src/graphics/ctexture.hpp @@ -94,14 +94,20 @@ class EE_API cTexture : public cImage { /** Save the Texture to a new File */ bool SaveToFile( const std::string& filepath, const EE_SAVETYPE& Format ); - /** Create an Alpha mask from a Color */ - void CreateMaskFromColor(eeColorA ColorKey, Uint8 Alpha); - - /** Create an Alpha mask from a Color */ - void CreateMaskFromColor(eeColor ColorKey, Uint8 Alpha); - /** Replace a color on the texture */ - void ReplaceColor(eeColorA ColorKey, eeColorA NewColor); + void ReplaceColor( const eeColorA& ColorKey, const eeColorA& NewColor); + + /** Create an Alpha mask from a Color */ + void CreateMaskFromColor( const eeColorA& ColorKey, Uint8 Alpha ); + + /** Fill a texture with a color */ + void FillWithColor( const eeColorA& Color ); + + /** Resize the texture */ + void Resize( const eeUint& new_width, const eeUint& new_height ); + + /** Copy an image inside the texture */ + void CopyImage( cImage * Img, const eeUint& x, const eeUint& y ); /** @return If the Texture has a copy on the local memory */ bool LocalCopy(); diff --git a/src/graphics/ctexturegrouploader.cpp b/src/graphics/ctexturegrouploader.cpp new file mode 100644 index 000000000..787612fdd --- /dev/null +++ b/src/graphics/ctexturegrouploader.cpp @@ -0,0 +1,129 @@ +#include "ctexturegrouploader.hpp" +#include "cshapegroup.hpp" +#include "cshapegroupmanager.hpp" + +namespace EE { namespace Graphics { + +cTextureGroupLoader::cTextureGroupLoader() : + mThreaded(false), + mLoaded(false), + mAppPath( AppPath() ) +{ +} + +cTextureGroupLoader::cTextureGroupLoader( const std::string& TextureGroupPath, const bool& Threaded ) : + mTextureGroupPath( TextureGroupPath ), + mThreaded( Threaded ), + mLoaded(false), + mAppPath( AppPath() ) +{ + Load(); +} + +cTextureGroupLoader::~cTextureGroupLoader() +{ +} + +void cTextureGroupLoader::Update() { + mRL.Update(); + + if ( mRL.IsLoaded() && !mLoaded ) + CreateShapes(); +} + +void cTextureGroupLoader::Load( const std::string& TextureGroupPath ) { + mRL.Threaded( mThreaded ); + + if ( TextureGroupPath.size() ) + mTextureGroupPath = TextureGroupPath; + + sTextureGroupHdr TexGrHdr; + + std::fstream fs ( mTextureGroupPath.c_str() , std::ios::in | std::ios::binary ); + + if ( fs.is_open() ) { + fs.read( reinterpret_cast (&TexGrHdr), sizeof(sTextureGroupHdr) ); + + if ( TexGrHdr.Magic == ( ( 'E' << 0 ) | ( 'E' << 8 ) | ( 'T' << 16 ) | ( 'G' << 24 ) ) ) { + for ( Uint32 i = 0; i < TexGrHdr.TextureCount; i++ ) { + sTextureHdr tTextureHdr; + sTempTexGroup tTexGroup; + + fs.read( reinterpret_cast (&tTextureHdr), sizeof(sTextureHdr) ); + + tTexGroup.Texture = tTextureHdr; + tTexGroup.Shapes.resize( tTextureHdr.ShapeCount ); + + std::string name( &tTextureHdr.Name[0] ); + std::string path( FileRemoveFileName( mTextureGroupPath ) + name ); + + mRL.Add( new cTextureLoader( path ) ); + + fs.read( reinterpret_cast (&tTexGroup.Shapes[0]), sizeof(sShapeHdr) * tTextureHdr.ShapeCount ); + + mTempGroups.push_back( tTexGroup ); + } + } + + mRL.Load(); + + if ( !mThreaded ) + CreateShapes(); + } +} + +void cTextureGroupLoader::CreateShapes() { + cShapeGroup * tSG = NULL; + + for ( Uint32 z = 0; z < mTempGroups.size(); z++ ) { + sTempTexGroup * tTexGroup = &mTempGroups[z]; + sTextureHdr * tTexHdr = &tTexGroup->Texture; + + std::string name( &tTexHdr->Name[0] ); + std::string path( FileRemoveFileName( mTextureGroupPath ) + name ); + + Int32 pos = StrStartsWith( mAppPath, path ); + + if ( -1 != pos && (Uint32)(pos + 1) < path.size() ) + path = path.substr( pos + 1 ); + + cTexture * tTex = cTextureFactory::instance()->GetByName( path ); + + // Create the Shape Group with the name of the real texture, not the Childs ( example load 1.png and not 1_ch1.png ) + if ( 0 == z ) { + tSG = new cShapeGroup( name ); + cShapeGroupManager::instance()->Add( tSG ); + } + + if ( NULL != tTex ) { + for ( Int32 i = 0; i < tTexHdr->ShapeCount; i++ ) { + sShapeHdr * tSh = &tTexGroup->Shapes[i]; + + std::string ShapeName( &tSh->Name[0] ); + eeRecti tRect( tSh->X, tSh->Y, tSh->X + tSh->Width, tSh->Y + tSh->Height ); + + tSG->Add( new cShape( tTex->TexId(), tRect, tSh->DestWidth, tSh->DestHeight, tSh->OffsetX, tSh->OffsetY, ShapeName ) ); + } + } else { + /** @TODO: Error Report */ + return; + } + } + + mLoaded = true; +} + +bool cTextureGroupLoader::Threaded() const { + return mThreaded; +} + +void cTextureGroupLoader::Threaded( const bool& threaded ) { + mThreaded = threaded; +} + +const bool& cTextureGroupLoader::IsLoaded() const { + return mLoaded; +} + +}} + diff --git a/src/graphics/ctexturegrouploader.hpp b/src/graphics/ctexturegrouploader.hpp new file mode 100644 index 000000000..2359b1b06 --- /dev/null +++ b/src/graphics/ctexturegrouploader.hpp @@ -0,0 +1,50 @@ +#ifndef EE_GRAPHICSCTEXTUREGROUPLOADER_HPP +#define EE_GRAPHICSCTEXTUREGROUPLOADER_HPP + +#include "base.hpp" +#include "packerhelper.hpp" +#include "ctextureloader.hpp" +#include "ctexturefactory.hpp" +#include "../system/cresourceloader.hpp" + +namespace EE { namespace Graphics { + +using namespace Private; + +class EE_API cTextureGroupLoader { + public: + cTextureGroupLoader(); + + cTextureGroupLoader( const std::string& TextureGroupPath, const bool& Threaded = false ); + + ~cTextureGroupLoader(); + + void Update(); + + void Load( const std::string& TextureGroupPath = "" ); + + bool Threaded() const; + + void Threaded( const bool& threaded ); + + const bool& IsLoaded() const; + protected: + cResourceLoader mRL; + std::string mTextureGroupPath; + bool mThreaded; + bool mLoaded; + std::string mAppPath; + + typedef struct sTempTexGroupS { + sTextureHdr Texture; + std::vector Shapes; + } sTempTexGroup; + + std::vector mTempGroups; + + void CreateShapes(); +}; + +}} + +#endif diff --git a/src/graphics/ctextureloader.cpp b/src/graphics/ctextureloader.cpp index 2c7175d23..5ad63dce9 100644 --- a/src/graphics/ctextureloader.cpp +++ b/src/graphics/ctextureloader.cpp @@ -1,5 +1,6 @@ #include "ctextureloader.hpp" #include "ctexturefactory.hpp" +#define STBI_TYPE_SPECIFIC_FUNCTIONS #include "../helper/SOIL/stb_image.h" #include "../helper/SOIL/SOIL.h" diff --git a/src/graphics/ctexturepacker.cpp b/src/graphics/ctexturepacker.cpp new file mode 100644 index 000000000..7561dda5f --- /dev/null +++ b/src/graphics/ctexturepacker.cpp @@ -0,0 +1,670 @@ +#include "ctexturepacker.hpp" +#include "cimage.hpp" +#include "../helper/SOIL/SOIL.h" + +namespace EE { namespace Graphics { + +cTexturePacker::cTexturePacker() : + mLongestEdge(0), + mTotalArea(0), + mFreeList(NULL), + mWidth(0), + mHeight(0), + mPacked(false), + mAllowFlipping(false), + mChild(NULL), + mStrategy(PackBig), + mCount(0), + mParent(NULL), + mPlacedCount(0) +{ +} + +cTexturePacker::~cTexturePacker() +{ + Close(); +} + +void cTexturePacker::Close() { + mLongestEdge = 0; + mTotalArea = 0; + mTextures.clear(); + + if ( NULL != mFreeList ) { + cTexturePackerNode * next = mFreeList; + cTexturePackerNode * kill = NULL; + + while ( NULL != next ) { + kill = next; + + next = next->GetNext(); + + eeSAFE_DELETE( kill ); + } + } + + eeSAFE_DELETE( mChild ); +} + +void cTexturePacker::NewFree( Int32 x, Int32 y, Int32 width, Int32 height ) { + cTexturePackerNode * node = new cTexturePackerNode( x, y, width, height ); + node->SetNext( mFreeList ); + mFreeList = node; +} + +bool cTexturePacker::MergeNodes() { + cTexturePackerNode *f = mFreeList; + + while ( f ) { + cTexturePackerNode * prev = 0; + cTexturePackerNode * c = mFreeList; + + while ( c ) { + if ( f != c ) { + if ( f->Merge( *c ) ) { + assert( prev ); + + prev->SetNext( c->GetNext() ); + + eeSAFE_DELETE( c ); + + return true; + } + } + + prev = c; + c = c->GetNext(); + } + + f = f->GetNext(); + } + + return false; +} + +void cTexturePacker::Validate() { +#ifdef EE_DEBUG + cTexturePackerNode * f = mFreeList; + while ( f ) { + cTexturePackerNode * c = mFreeList; + + while ( c ) { + if ( f != c ) + f->Validate(c); + + c = c->GetNext(); + } + + f = f->GetNext(); + } +#endif +} + +cTexturePackerTex * cTexturePacker::GetLonguestEdge() { + cTexturePackerTex * t = NULL; + std::list::iterator it; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + if ( !(*it).Placed() ) { + t = &(*it); + break; + } + } + + return t; +} + +cTexturePackerTex * cTexturePacker::GetShortestEdge() { + cTexturePackerTex * t = NULL; + std::list::reverse_iterator it; + + for ( it = mTextures.rbegin(); it != mTextures.rend(); it++ ) { + if ( !(*it).Placed() ) { + t = &(*it); + break; + } + } + + return t; +} + +void cTexturePacker::AddBorderToTextures( const Int32& BorderSize ) { + cTexturePackerTex * t; + + if ( 0 != BorderSize ) { + std::list::iterator it; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + t = &(*it); + + t->Width ( t->Width() + BorderSize ); + t->Height ( t->Height() + BorderSize ); + } + + mLongestEdge += BorderSize; + } +} + +cTexturePackerNode * cTexturePacker::GetBestFit( cTexturePackerTex * t, cTexturePackerNode ** prevBestFit, Int32 * EdgeCount ) { + Int32 leastY = 0x7FFFFFFF; + Int32 leastX = 0x7FFFFFFF; + cTexturePackerNode * previousBestFit = NULL; + cTexturePackerNode * bestFit = NULL; + cTexturePackerNode * previous = NULL; + cTexturePackerNode * search = mFreeList; + Int32 edgeCount = 0; + + // Walk the singly linked list of free nodes + // see if it will fit into any currently free space + while ( search ) { + Int32 ec; + + // see if the texture will fit into this slot, and if so how many edges does it share. + if ( search->Fits( t->Width(), t->Height(), ec, mAllowFlipping ) ) { + + if ( ec == 2 ) { + previousBestFit = previous; // record the pointer previous to this one (used to patch the linked list) + bestFit = search; // record the best fit. + edgeCount = ec; + + break; + } + + if ( search->Y() < leastY ) { + leastY = search->Y(); + leastX = search->X(); + previousBestFit = previous; + bestFit = search; + edgeCount = ec; + } else if ( search->Y() == leastY && search->X() < leastX ) { + leastX = search->X(); + previousBestFit = previous; + bestFit = search; + edgeCount = ec; + } + } + + previous = search; + search = search->GetNext(); + } + + *EdgeCount = edgeCount; + *prevBestFit = previousBestFit; + + return bestFit; +} + +void cTexturePacker::InsertTexture( cTexturePackerTex * t, cTexturePackerNode * bestFit, Int32 edgeCount, cTexturePackerNode * previousBestFit ) { + if ( NULL != bestFit ) { + Validate(); + + switch ( edgeCount ) { + case 0: + { + bool flipped = false; + int w = t->Width(); + int h = t->Height(); + + if ( mAllowFlipping ) { + if ( t->LongestEdge() <= bestFit->Width() ) { + if ( h > w ) { + w = t->Height(); + h = t->Width(); + flipped = true; + } + } else { + assert( t->LongestEdge() <= bestFit->Height() ); + + if ( h < w ) { + w = t->Height(); + h = t->Width(); + flipped = true; + } + } + } + + t->Place( bestFit->X(), bestFit->Y(), flipped ); // place it. + + NewFree( bestFit->X(), bestFit->Y() + h, bestFit->Width(), bestFit->Height() - h ); + + bestFit->X ( bestFit->X() + w ); + bestFit->Width ( bestFit->Width() - w ); + bestFit->Height ( h ); + + Validate(); + } + break; + case 1: + { + if ( t->Width() == bestFit->Width() ) { + t->Place( bestFit->X(), bestFit->Y(), false ); + + bestFit->Y ( bestFit->Y() + t->Height() ); + bestFit->Height ( bestFit->Height() - t->Height() ); + + Validate(); + } else if ( t->Height() == bestFit->Height() ) { + t->Place( bestFit->X(), bestFit->Y(), false ); + + bestFit->X ( bestFit->X() + t->Width() ); + bestFit->Width ( bestFit->Width() - t->Width() ); + + Validate(); + } else if ( mAllowFlipping && t->Width() == bestFit->Height() ) { + t->Place( bestFit->X(), bestFit->Y(), true ); + + bestFit->X ( bestFit->X() + t->Height() ); + bestFit->Width ( bestFit->Width() - t->Height() ); + + Validate(); + } else if ( mAllowFlipping && t->Height() == bestFit->Width() ) { + t->Place( bestFit->X(), bestFit->Y(), true ); + + bestFit->Y ( bestFit->Y() + t->Width() ); + bestFit->Height ( bestFit->Height() - t->Width() ); + + Validate(); + } + } + break; + case 2: + { + bool flipped = t->Width() != bestFit->Width() || t->Height() != bestFit->Height(); + + t->Place( bestFit->X(), bestFit->Y(), flipped ); + + if ( previousBestFit ) + previousBestFit->SetNext( bestFit->GetNext() ); + else + mFreeList = bestFit->GetNext(); + + eeSAFE_DELETE( bestFit ); + + Validate(); + } + break; + } + + while ( MergeNodes() ); // keep merging nodes as much as we can... + } +} + +void cTexturePacker::CreateChild( const Uint32& MaxWidth, const Uint32& MaxHeight, const bool& ForcePowOfTwo, const Uint32& PixelBorder, const bool& AllowFlipping ) { + mChild = new cTexturePacker(); + + std::list::iterator it; + cTexturePackerTex * t = NULL; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + t = &(*it); + + if ( !t->Placed() ) { + mChild->AddTexture( t->Name() ); + mChild->mParent = this; + + t->Disabled( true ); + + mCount--; + } + } + + mChild->PackTextures( MaxWidth, MaxHeight, ForcePowOfTwo, PixelBorder, AllowFlipping ); +} + +bool cTexturePacker::AddTexturesPath( std::string TexturesPath ) { + if ( IsDirectory( TexturesPath ) ) { + + if ( TexturesPath[ TexturesPath.size() - 1 ] != '/' && TexturesPath[ TexturesPath.size() - 1 ] != '\\' ) + TexturesPath += "/"; + + std::vector files = FilesGetInPath( TexturesPath ); + std::sort( files.begin(), files.end() ); + + for ( Uint32 i = 0; i < files.size(); i++ ) { + std::string path( TexturesPath + files[i] ); + if ( !IsDirectory( path ) ) + AddTexture( path ); + } + + return true; + } + + return false; +} + +bool cTexturePacker::AddTexture( const std::string& TexturePath ) { + if ( FileExists( TexturePath ) ) { + cTexturePackerTex TPack( TexturePath ); + + if ( TPack.LoadedInfo() ) { + if ( TPack.Width() > mLongestEdge ) + mLongestEdge = TPack.Width(); + + if ( TPack.Height() > mLongestEdge ) + mLongestEdge = TPack.Height(); + + mTotalArea += TPack.Area(); + + // Insert ordered + std::list::iterator it; + + bool Added = false; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + if ( (*it).Area() < TPack.Area() ) { + mTextures.insert( it, TPack ); + Added = true; + break; + } + } + + if ( !Added ) { + mTextures.push_back( TPack ); + + return true; + } + } + } + + return false; +} + +Int32 cTexturePacker::PackTextures( const Uint32& MaxWidth, const Uint32& MaxHeight, const bool& ForcePowOfTwo, const Uint32& PixelBorder, const bool& AllowFlipping ) { // pack the textures, the return code is the amount of wasted/unused area. + mAllowFlipping = AllowFlipping; + Int32 Width = MaxWidth; + Int32 Height = MaxHeight; + cTexturePackerTex * t = NULL; + + AddBorderToTextures( (Int32)PixelBorder ); + + if ( ForcePowOfTwo && !IsPow2( Width ) ) + Width = NextPowOfTwo( Width ); + + if ( ForcePowOfTwo && !IsPow2( Height ) ) + Height = NextPowOfTwo( Height ); + + NewFree( 0, 0, Width, Height ); + + mCount = mTextures.size(); + + // We must place each texture + std::list::iterator it; + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + // For the texture with the longest edge we place it according to this criteria. + // (1) If it is a perfect match, we always accept it as it causes the least amount of fragmentation. + // (2) A match of one edge with the minimum area left over after the split. + // (3) No edges match, so look for the node which leaves the least amount of area left over after the split. + + if ( PackBig == mStrategy ) + t = GetLonguestEdge(); + else if ( PackTiny == mStrategy ) + t = GetShortestEdge(); + + cTexturePackerNode * previousBestFit = NULL; + Int32 edgeCount = 0; + cTexturePackerNode * bestFit = GetBestFit( t, &previousBestFit, &edgeCount ); + + if ( NULL == bestFit ) { + if ( PackBig == mStrategy ) { + mStrategy = PackTiny; + #ifdef EE_DEBUG + printf( "Chaging Strategy to Tiny. %s faults.\n", t->Name().c_str() ); + #endif + } else if ( PackTiny == mStrategy ) { + mStrategy = PackFail; + #ifdef EE_DEBUG + printf( "Strategy fail, must create a new image. %s faults.\n", t->Name().c_str() ); + #endif + } + } else { + InsertTexture( t, bestFit, edgeCount, previousBestFit ); + mCount--; + } + + if ( PackFail == mStrategy ) { + #ifdef EE_DEBUG + printf( "Creating a new image as a child.\n" ); + #endif + CreateChild( MaxWidth, MaxHeight, ForcePowOfTwo, PixelBorder, AllowFlipping ); + break; + } + } + + if ( mCount > 0 ) { + #ifdef EE_DEBUG + printf( "Creating a new image as a child. Some textures couldn't get it: %d\n", mCount ); + #endif + CreateChild( MaxWidth, MaxHeight, ForcePowOfTwo, PixelBorder, AllowFlipping ); + } + + AddBorderToTextures( -( (Int32)PixelBorder ) ); + + if ( ForcePowOfTwo ) + Height = NextPowOfTwo( Height ); + + mWidth = Width; + mHeight = Height; + mPacked = true; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + if ( !(*it).Placed() ) + mTotalArea -= (*it).Area(); + } + + #ifdef EE_DEBUG + printf( "Total Area Used: %d. This represents the %4.2f percent \n", mTotalArea, ( (eeDouble)mTotalArea / (eeDouble)( mWidth * mHeight ) ) * 100.0 ); + #endif + + return ( Width * Height ) - mTotalArea; +} + +void cTexturePacker::Save( const std::string& Filepath, const EE_SAVETYPE& Format ) { + mFilepath = Filepath; + + cImage Img( (Uint32)mWidth, (Uint32)mHeight, (Uint32)4 ); + + Img.FillWithColor( eeColorA(0,0,0,0) ); + + cTexturePackerTex * t = NULL; + int w, h, c; + std::list::iterator it; + + for ( it = mTextures.begin(); it != mTextures.end(); it++ ) { + t = &(*it); + + if ( t->Placed() ) { + Uint8 * data = SOIL_load_image( t->Name().c_str(), &w, &h, &c, 0 ); + + if ( NULL != data && t->Width() == w && t->Height() == h ) { + cImage * ImgCopy = new cImage( data, w, h, c ); + + Img.CopyImage( ImgCopy, t->X(), t->Y() ); + + ImgCopy->AvoidFreeImage( true ); + + eeSAFE_DELETE( ImgCopy ); + + SOIL_free_image_data( data ); + + mPlacedCount++; + } + } + } + + Img.SaveToFile( Filepath, Format ); + + ChildSave( Format ); + + SaveShapes(); +} + +Int32 cTexturePacker::GetChildCount() { + cTexturePacker * Child = mChild; + Int32 ChildCount = 0; + + while ( NULL != Child ) { + ChildCount++; + Child = Child->GetChild(); + } + + return ChildCount; +} + +void cTexturePacker::SaveShapes() { + if ( NULL != mParent ) + return; + + sTextureGroupHdr TexGrHdr; + + TexGrHdr.Magic = ( ( 'E' << 0 ) | ( 'E' << 8 ) | ( 'T' << 16 ) | ( 'G' << 24 ) ); + TexGrHdr.TextureCount = 1 + GetChildCount(); + + sTextureHdr TexHdr[ TexGrHdr.TextureCount ]; + + TexHdr[ 0 ] = CreateTextureHdr( this ); + + Int32 HdrPos = 1; + cTexturePacker * Child = mChild; + + while ( NULL != Child ) { + TexHdr[ HdrPos ] = CreateTextureHdr( Child ); + Child = Child->GetChild(); + HdrPos++; + } + + std::vector tShapesHdr; + + std::string path = FileRemoveExtension( mFilepath ) + ".etg"; + std::fstream fs ( path.c_str() , std::ios::out | std::ios::binary ); + + if ( fs.is_open() ) { + fs.write( reinterpret_cast (&TexGrHdr), sizeof(sTextureGroupHdr) ); + + fs.write( reinterpret_cast (&TexHdr[ 0 ]), sizeof(sTextureHdr) ); + + CreateShapesHdr( this, tShapesHdr, &fs ); + + if ( tShapesHdr.size() ) + fs.write( reinterpret_cast (&tShapesHdr[ 0 ]), sizeof(sShapeHdr) * tShapesHdr.size() ); + + Int32 HdrPos = 1; + cTexturePacker * Child = mChild; + + while ( NULL != Child ) { + fs.write( reinterpret_cast (&TexHdr[ HdrPos ]), sizeof(sTextureHdr) ); + + CreateShapesHdr( Child, tShapesHdr, &fs ); + + if ( tShapesHdr.size() ) + fs.write( reinterpret_cast (&tShapesHdr[ 0 ]), sizeof(sShapeHdr) * tShapesHdr.size() ); + + Child = Child->GetChild(); + + HdrPos++; + } + + fs.close(); + } +} + +void cTexturePacker::CreateShapesHdr( cTexturePacker * Packer, std::vector& Shapes, std::fstream * fs ) { + Shapes.clear(); + + sShapeHdr tShapeHdr; + + std::list tTextures = *(Packer->GetTexturePackPtr()); + std::list::iterator it; + cTexturePackerTex * tTex; + + for ( it = tTextures.begin(); it != tTextures.end(); it++ ) { + tTex = &(*it); + + if ( tTex->Placed() ) { + std::string name = FileNameFromPath(tTex->Name() ); + + memset( tShapeHdr.Name, 0, HDR_NAME_SIZE ); + StrCopy( tShapeHdr.Name, name.c_str(), HDR_NAME_SIZE ); + + tShapeHdr.ResourceID = MakeHash( name ); + tShapeHdr.Width = tTex->Width(); + tShapeHdr.Height = tTex->Height(); + tShapeHdr.DestWidth = tTex->Width(); + tShapeHdr.DestHeight = tTex->Height(); + tShapeHdr.OffsetX = 0; + tShapeHdr.OffsetY = 0; + tShapeHdr.X = tTex->X(); + tShapeHdr.Y = tTex->Y(); + tShapeHdr.Date = FileGetModificationDate( tTex->Name() ); + + fs->write( reinterpret_cast (&tShapeHdr), sizeof(sShapeHdr) ); + } + } +} + +sTextureHdr cTexturePacker::CreateTextureHdr( cTexturePacker * Packer ) { + sTextureHdr TexHdr; + + std::string name( FileNameFromPath( Packer->GetFilepath() ) ); + + memset( TexHdr.Name, 0, HDR_NAME_SIZE ); + StrCopy( TexHdr.Name, name.c_str(), HDR_NAME_SIZE ); + + TexHdr.ResourceID = MakeHash( name ); + TexHdr.Size = FileSize( Packer->GetFilepath() ); + TexHdr.Width = Packer->GetWidth(); + TexHdr.Height = Packer->GetHeight(); + TexHdr.ShapeCount = Packer->GetPlacedCount(); + + return TexHdr; +} + +void cTexturePacker::ChildSave( const EE_SAVETYPE& Format ) { + if ( NULL != mChild ) { + cTexturePacker * Parent = mChild->GetParent(); + cTexturePacker * LastParent = NULL; + Int32 ParentCount = 0; + + // Find the grand parent + while ( NULL != Parent ) { + ParentCount++; + LastParent = Parent; + Parent = Parent->GetParent(); + } + + std::string fFpath = FileRemoveExtension( LastParent->GetFilepath() ); + std::string fExt = FileExtension( LastParent->GetFilepath() ); + std::string fName = fFpath + "_ch" + toStr( ParentCount ) + "." + fExt; + + mChild->Save( fName, Format ); + } +} + +cTexturePacker * cTexturePacker::GetChild() const { + return mChild; +} + +cTexturePacker * cTexturePacker::GetParent() const { + return mParent; +} + +std::list * cTexturePacker::GetTexturePackPtr() { + return &mTextures; +} + +const std::string& cTexturePacker::GetFilepath() const { + return mFilepath; +} + +const Int32& cTexturePacker::GetWidth() const { + return mWidth; +} + +const Int32& cTexturePacker::GetHeight() const { + return mHeight; +} + +const Int32& cTexturePacker::GetPlacedCount() const { + return mPlacedCount; +} + +}} diff --git a/src/graphics/ctexturepacker.hpp b/src/graphics/ctexturepacker.hpp new file mode 100644 index 000000000..eef272135 --- /dev/null +++ b/src/graphics/ctexturepacker.hpp @@ -0,0 +1,130 @@ +#ifndef EE_GRAPHICSCTEXTUREATLAS +#define EE_GRAPHICSCTEXTUREATLAS + +/*! +** +** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com +** +** The MIT license: +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is furnished +** to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. + +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +/*! NOTE by Martin Lucas Golini +** This implementation is based on the John W. Ratcliff texture atlas implementation. +** Implementation differ from the original, but i use the base texture atlas algorithm. +*/ + +#include "base.hpp" +#include "packerhelper.hpp" +#include "ctexturepackernode.hpp" +#include "ctexturepackertex.hpp" + +namespace EE { namespace Graphics { + +using namespace Private; + +class EE_API cTexturePacker { + public: + cTexturePacker(); + + ~cTexturePacker(); + + bool AddTexture( const std::string& TexturePath ); + + bool AddTexturesPath( std::string TexturesPath ); + + Int32 PackTextures( const Uint32& MaxWidth, const Uint32& MaxHeight, const bool& ForcePowOfTwo = true, const Uint32& PixelBorder = 0, const bool& AllowFlipping = false ); + + void Save( const std::string& Filepath, const EE_SAVETYPE& Format = EE_SAVE_TYPE_DDS ); + + void Close(); + + inline const Int32& Width() const { return mWidth; } + + inline const Int32& Height() const { return mHeight; } + protected: + enum PackStrategy { + PackBig, + PackTiny, + PackFail + }; + + std::list mTextures; + + Int32 mLongestEdge; + Int32 mTotalArea; + cTexturePackerNode * mFreeList; + Int32 mWidth; + Int32 mHeight; + bool mPacked; + bool mAllowFlipping; + cTexturePacker * mChild; + Int32 mStrategy; + Int32 mCount; + cTexturePacker * mParent; + std::string mFilepath; + Int32 mPlacedCount; + + cTexturePacker * GetChild() const; + + cTexturePacker * GetParent() const; + + std::list * GetTexturePackPtr(); + + const std::string& GetFilepath() const; + + void ChildSave( const EE_SAVETYPE& Format ); + + void SaveShapes(); + + void NewFree( Int32 x, Int32 y, Int32 width, Int32 height ); + + bool MergeNodes(); + + void Validate(); + + cTexturePackerTex * GetLonguestEdge(); + + cTexturePackerTex * GetShortestEdge(); + + Int32 GetChildCount(); + + const Int32& GetWidth() const; + + const Int32& GetHeight() const; + + const Int32& GetPlacedCount() const; + + sTextureHdr CreateTextureHdr( cTexturePacker * Packer ); + + void CreateShapesHdr( cTexturePacker * Packer, std::vector& Shapes, std::fstream * fs ); + + cTexturePackerNode * GetBestFit( cTexturePackerTex * t, cTexturePackerNode ** prevBestFit, Int32 * EdgeCount ); + + void InsertTexture( cTexturePackerTex * t, cTexturePackerNode * bestFit, Int32 edgeCount, cTexturePackerNode * previousBestFit ); + + void AddBorderToTextures( const Int32& BorderSize ); + + void CreateChild( const Uint32& MaxWidth, const Uint32& MaxHeight, const bool& ForcePowOfTwo, const Uint32& PixelBorder, const bool& AllowFlipping ); +}; + +}} + +#endif diff --git a/src/graphics/ctexturepackernode.cpp b/src/graphics/ctexturepackernode.cpp new file mode 100644 index 000000000..14a97c6e6 --- /dev/null +++ b/src/graphics/ctexturepackernode.cpp @@ -0,0 +1,100 @@ +#include "ctexturepackernode.hpp" + +namespace EE { namespace Graphics { namespace Private { + +cTexturePackerNode::cTexturePackerNode( Int32 x, Int32 y, Int32 width, Int32 height ) { + mX = x; + mY = y; + mWidth = width; + mHeight = height; + mNext = NULL; +} + +cTexturePackerNode * cTexturePackerNode::GetNext() const { + return mNext; +} + +bool cTexturePackerNode::Fits( Int32 width, Int32 height, Int32 &edgeCount, const bool& AllowFlipping ) const { + bool ret = false; + + edgeCount = 0; + + if ( width == mWidth || height == mHeight || width == mHeight || height == mWidth ) { + if ( width == mWidth ) { + edgeCount++; + if ( height == mHeight ) edgeCount++; + } + else if ( AllowFlipping && width == mHeight ) { + edgeCount++; + if ( height == mWidth ) edgeCount++; + } + else if ( AllowFlipping && height == mWidth ) { + edgeCount++; + } + else if ( height == mHeight ) { + edgeCount++; + } + } + + if ( width <= mWidth && height <= mHeight ) { + ret = true; + } else if ( AllowFlipping && height <= mWidth && width <= mHeight ) { + ret = true; + } + + return ret; +} + +void cTexturePackerNode::GetRect( eeRecti &r ) const { + r = eeRecti( mX, mY, mX + mWidth - 1, mY + mHeight - 1 ); +} + +void cTexturePackerNode::Validate( cTexturePackerNode * n ) { + eeRecti r1; + eeRecti r2; + GetRect( r1 ); + n->GetRect( r2 ); + assert( !r1.Intersect(r2) ); +} + +bool cTexturePackerNode::Merge( const cTexturePackerNode& n ) { + bool ret = false; + + eeRecti r1; + eeRecti r2; + + GetRect( r1 ); + n.GetRect( r2 ); + + r1.Right++; + r1.Bottom++; + r2.Right++; + r2.Bottom++; + + if ( r1.Left == r2.Left && r1.Right == r2.Right && r1.Top == r2.Bottom ) // if we share the top edge then.. + { + mY = n.Y(); + mHeight += n.Height(); + ret = true; + } + else if ( r1.Left == r2.Left && r1.Right == r2.Right && r1.Bottom == r2.Top ) // if we share the bottom edge + { + mHeight += n.Height(); + ret = true; + } + else if ( r1.Top == r2.Top && r1.Bottom == r2.Top && r1.Left == r2.Right ) // if we share the left edge + { + mX = n.X(); + mWidth += n.Width(); + ret = true; + } + else if ( r1.Top == r2.Top && r1.Bottom == r2.Top && r1.Right == r2.Left ) // if we share the left edge + { + mWidth += n.Width(); + ret = true; + } + + return ret; +} + +}}} diff --git a/src/graphics/ctexturepackernode.hpp b/src/graphics/ctexturepackernode.hpp new file mode 100644 index 000000000..a6e393718 --- /dev/null +++ b/src/graphics/ctexturepackernode.hpp @@ -0,0 +1,49 @@ +#ifndef EE_GRAPHICSPRIVATECTEXTUREPACKERNODE +#define EE_GRAPHICSPRIVATECTEXTUREPACKERNODE + +#include "base.hpp" + +namespace EE { namespace Graphics { namespace Private { + +class cTexturePackerNode { + public: + cTexturePackerNode( Int32 x, Int32 y, Int32 width, Int32 height ); + + bool Fits( Int32 wid, Int32 hit, Int32 &edgeCount, const bool& AllowFlipping = false ) const; + + void GetRect( eeRecti &r ) const; + + void Validate( cTexturePackerNode * n ); + + bool Merge( const cTexturePackerNode &n ); + + cTexturePackerNode * GetNext() const; + + inline void SetNext( cTexturePackerNode * Next ) { mNext = Next; } + + inline const Int32& X() const { return mX; } + + inline const Int32& Y() const { return mY; } + + inline void X( const Int32& x ) { mX = x; } + + inline void Y( const Int32& y ) { mY = y; } + + inline const Int32& Width() const { return mWidth; } + + inline const Int32& Height() const { return mHeight; } + + inline void Width( const Int32& W ) { mWidth = W; } + + inline void Height( const Int32& H ) { mHeight = H; } + protected: + cTexturePackerNode * mNext; + Int32 mX; + Int32 mY; + Int32 mWidth; + Int32 mHeight; +}; + +}}} + +#endif diff --git a/src/graphics/ctexturepackertex.cpp b/src/graphics/ctexturepackertex.cpp new file mode 100644 index 000000000..67a4be16f --- /dev/null +++ b/src/graphics/ctexturepackertex.cpp @@ -0,0 +1,38 @@ +#include "ctexturepackertex.hpp" +#include "../helper/SOIL/stb_image.h" + +namespace EE { namespace Graphics { namespace Private { + +cTexturePackerTex::cTexturePackerTex( const std::string& Name ) : + mName(Name), + mWidth(0), + mHeight(0), + mX(0), + mY(0), + mLongestEdge(0), + mArea(0), + mFlipped(false), + mPlaced(false), + mLoadedInfo(false), + mDisabled(false) +{ + Int32 c; + + if ( stbi_info( Name.c_str(), &mWidth, &mHeight, &c ) ) { + mArea = mWidth * mHeight; + mLongestEdge = ( mWidth >= mHeight ) ? mWidth : mHeight; + mLoadedInfo = true; + } +} + +void cTexturePackerTex::Place( Int32 x, Int32 y, bool flipped ) { + if ( !mPlaced ) { + mX = x; + mY = y; + mFlipped = flipped; + mPlaced = true; + } +} + +}}} + diff --git a/src/graphics/ctexturepackertex.hpp b/src/graphics/ctexturepackertex.hpp new file mode 100644 index 000000000..8510aff28 --- /dev/null +++ b/src/graphics/ctexturepackertex.hpp @@ -0,0 +1,61 @@ +#ifndef EE_GRAPHICSPRIVATECTEXTUREPACKERTEX +#define EE_GRAPHICSPRIVATECTEXTUREPACKERTEX + +#include "base.hpp" + +namespace EE { namespace Graphics { namespace Private { + +class cTexturePackerTex { + public: + cTexturePackerTex( const std::string& Name ); + + void Place( Int32 x, Int32 y, bool flipped ); + + inline const std::string& Name() const { return mName; } + + inline const Int32& X() const { return mX; } + + inline const Int32& Y() const { return mY; } + + inline void X( const Int32& x ) { mX = x; } + + inline void Y( const Int32& y ) { mY = y; } + + inline const Int32& Width() const { return mWidth; } + + inline const Int32& Height() const { return mHeight; } + + inline void Width( const Int32& W ) { mWidth = W; } + + inline void Height( const Int32& H ) { mHeight = H; } + + inline const bool& LoadedInfo() const { return mLoadedInfo; } + + inline const Int32& Area() const { return mArea; } + + inline const bool& Placed() const { return mPlaced; } + + inline const bool& Flipped() const { return mFlipped; } + + inline const Int32& LongestEdge() const { return mLongestEdge; } + + inline const bool& Disabled() const { return mDisabled; } + + inline void Disabled( const bool& d ) { mDisabled = d; } + protected: + std::string mName; + Int32 mWidth; + Int32 mHeight; + Int32 mX; + Int32 mY; + Int32 mLongestEdge; + Int32 mArea; + bool mFlipped; + bool mPlaced; + bool mLoadedInfo; + bool mDisabled; +}; + +}}} + +#endif diff --git a/src/graphics/packerhelper.hpp b/src/graphics/packerhelper.hpp new file mode 100644 index 000000000..6376c2140 --- /dev/null +++ b/src/graphics/packerhelper.hpp @@ -0,0 +1,40 @@ +#ifndef EE_PACKER_HELPER +#define EE_PACKER_HELPER + +#include "base.hpp" + +namespace EE { namespace Graphics { namespace Private { + +#define HDR_NAME_SIZE 64 + +typedef struct sShapeHdrS { + char Name[ HDR_NAME_SIZE ]; + Uint32 Date; + Int32 X; + Int32 Y; + Int32 Width; + Int32 Height; + Uint32 ResourceID; + Int32 OffsetX; + Int32 OffsetY; + Int32 DestWidth; + Int32 DestHeight; +} sShapeHdr; + +typedef struct sTextureHdrS { + char Name[ HDR_NAME_SIZE ]; + Uint32 ResourceID; + Uint32 Size; + Int32 Width; + Int32 Height; + Int32 ShapeCount; +} sTextureHdr; + +typedef struct sTextureGroupHdrS { + Uint32 Magic; + Uint32 TextureCount; +} sTextureGroupHdr; + +}}} + +#endif diff --git a/src/helper/SOIL/stb_image.c b/src/helper/SOIL/stb_image.c index 6907820a2..0c5d96ea9 100644 --- a/src/helper/SOIL/stb_image.c +++ b/src/helper/SOIL/stb_image.c @@ -1,4 +1,4 @@ -/* stbi-1.28 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c +/* stbi-1.29 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c when you control the images you're loading no warranty implied; use at your own risk @@ -20,7 +20,9 @@ - decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) - supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) - Latest revisions: + Latest revisions: + 1.30 (2010-08-18) added stbi_info support for BMP,PSD,HDR,PIC by Martin Golini + 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) cast-to-uint8 to fix warnings (Laurent Gomila) allow trailing 0s at end of image data (Laurent Gomila) @@ -42,7 +44,6 @@ See end of file for full revision history. TODO: - stbi_info support for BMP,PSD,HDR,PIC rewrite stbi_info and load_file variations to share file handling code (current system allows individual functions to be called directly, since each does all the work, but I doubt anyone uses this in practice) @@ -62,6 +63,8 @@ Extensions, features Janez Zemva Jetro Lauha (stbi_info) Jonathan Blow James "moose2000" Brown (iPhone PNG) Laurent Gomila + Aruelien Pocheville + Martin Golini If your name should be here but isn't, let Sean know. @@ -108,10 +111,6 @@ typedef unsigned char validate_uint32[sizeof(uint32)==4 ? 1 : -1]; #define STBI_NO_WRITE #endif -#ifndef STBI_NO_DDS -#include "stbi_DDS.h" -#endif - #define STBI_NOTUSED(v) v=v #ifdef _MSC_VER @@ -162,10 +161,15 @@ extern int stbi_png_info_from_file (FILE *f, int *x, int extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_bmp_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_bmp_test_file (FILE *f); -extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_bmp_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_bmp_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a tga? @@ -182,30 +186,45 @@ extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_psd_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_psd_test_file (FILE *f); -extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_psd_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_psd_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it an hdr? extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_hdr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_hdr_test_file (FILE *f); -extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_hdr_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_hdr_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a pic? extern int stbi_pic_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_pic_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_pic_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_pic_test_file (FILE *f); -extern stbi_uc *stbi_pic_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_pic_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_pic_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_pic_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a gif? @@ -221,7 +240,10 @@ extern stbi_uc *stbi_gif_load_from_file (FILE *f, int *x, int extern int stbi_gif_info (char const *filename, int *x, int *y, int *comp); extern int stbi_gif_info_from_file (FILE *f, int *x, int *y, int *comp); #endif - + +#ifndef STBI_NO_DDS +#include "stbi_DDS.h" +#endif // this is not threadsafe static const char *failure_reason; @@ -400,6 +422,8 @@ int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) #ifndef STBI_NO_HDR return stbi_hdr_test_memory(buffer, len); #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); return 0; #endif } @@ -489,7 +513,7 @@ static void start_mem(stbi *s, uint8 const *buffer, int len) #ifndef STBI_NO_STDIO static void refill_buffer(stbi *s) { - int n = (int)fread(s->buffer_start, 1, s->buflen, s->img_file); + int n = fread(s->buffer_start, 1, s->buflen, s->img_file); if (n == 0) { s->from_file = 0; s->img_buffer = s->img_buffer_end-1; @@ -536,7 +560,7 @@ static void skip(stbi *s, int n) { #ifndef STBI_NO_STDIO if (s->img_file) { - int blen = (int)( s->img_buffer_end - s->img_buffer ); + int blen = s->img_buffer_end - s->img_buffer; if (blen < n) { s->img_buffer = s->img_buffer_end; fseek(s->img_file, n - blen, SEEK_CUR); @@ -551,7 +575,7 @@ static int getn(stbi *s, stbi_uc *buffer, int n) { #ifndef STBI_NO_STDIO if (s->img_file) { - int blen = (int)( s->img_buffer_end - s->img_buffer ); + int blen = s->img_buffer_end - s->img_buffer; if (blen < n) { int res; memcpy(buffer, s->img_buffer, blen); @@ -741,7 +765,7 @@ typedef struct typedef struct { - #if STBI_SIMD + #ifdef STBI_SIMD unsigned short dequant2[4][64]; #endif stbi s; @@ -1020,7 +1044,7 @@ __forceinline static uint8 clamp(int x) t1 += p2+p4; \ t0 += p1+p3; -#if STBI_SIMD +#ifdef STBI_SIMD typedef unsigned short stbi_dequantize_t; #else typedef uint8 stbi_dequantize_t; @@ -1135,7 +1159,7 @@ static int parse_entropy_coded_data(jpeg *z) reset(z); if (z->scan_n == 1) { int i,j; - #if STBI_SIMD + #ifdef STBI_SIMD __declspec(align(16)) #endif short data[64]; @@ -1149,7 +1173,7 @@ static int parse_entropy_coded_data(jpeg *z) for (j=0; j < h; ++j) { for (i=0; i < w; ++i) { if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; - #if STBI_SIMD + #ifdef STBI_SIMD stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); #else idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); @@ -1179,7 +1203,7 @@ static int parse_entropy_coded_data(jpeg *z) int x2 = (i*z->img_comp[n].h + x)*8; int y2 = (j*z->img_comp[n].v + y)*8; if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; - #if STBI_SIMD + #ifdef STBI_SIMD stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); #else idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); @@ -1227,7 +1251,7 @@ static int process_marker(jpeg *z, int m) if (t > 3) return e("bad DQT table","Corrupt JPEG"); for (i=0; i < 64; ++i) z->dequant[t][dezigzag[i]] = get8u(&z->s); - #if STBI_SIMD + #ifdef STBI_SIMD for (i=0; i < 64; ++i) z->dequant2[t][i] = z->dequant[t][i]; #endif @@ -1547,7 +1571,7 @@ static void YCbCr_to_RGB_row(uint8 *out, const uint8 *y, const uint8 *pcb, const } } -#if STBI_SIMD +#ifdef STBI_SIMD static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) @@ -1656,7 +1680,7 @@ static uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int re if (n >= 3) { uint8 *y = coutput[0]; if (z->s.img_n == 3) { - #if STBI_SIMD + #ifdef STBI_SIMD stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n); #else YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s.img_x, n); @@ -1704,9 +1728,18 @@ unsigned char *stbi_jpeg_load(char const *filename, int *x, int *y, int *comp, i unsigned char *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { + #ifdef STBI_SMALL_STACK + unsigned char *result; + jpeg *j = (jpeg *) malloc(sizeof(*j)); + start_mem(&j->s, buffer, len); + result = load_jpeg_image(j,x,y,comp,req_comp); + free(j); + return result; + #else jpeg j; start_mem(&j.s, buffer,len); return load_jpeg_image(&j, x,y,comp,req_comp); + #endif } static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp) @@ -3061,7 +3094,7 @@ stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int stbi s; start_mem(&s, buffer, len); return bmp_load(&s, x,y,comp,req_comp); -} +} // Targa Truevision - TGA // by Jonathan Dummer @@ -3075,12 +3108,9 @@ static int tga_info(stbi *s, int *x, int *y, int *comp) if( sz > 1 ) return 0; // only RGB or indexed allowed sz = get8u(s); // image type // only RGB or grey allowed, +/- RLE - if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; - get16le(s); // discard palette start - get16le(s); // discard palette length - get8(s); // discard bits per palette color entry - get16le(s); // discard x origin - get16le(s); // discard y origin + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + skip(s,9); + tga_w = get16le(s); if( tga_w < 1 ) return 0; // test width tga_h = get16le(s); @@ -3095,6 +3125,7 @@ static int tga_info(stbi *s, int *x, int *y, int *comp) return 1; // seems to have passed everything } +#ifndef STBI_NO_STDIO int stbi_tga_info_from_file(FILE *f, int *x, int *y, int *comp) { stbi s; @@ -3105,6 +3136,7 @@ int stbi_tga_info_from_file(FILE *f, int *x, int *y, int *comp) fseek(f, n, SEEK_SET); return r; } +#endif int stbi_tga_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) { @@ -4500,11 +4532,20 @@ int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) if (stbi_png_info_from_file(f, x, y, comp)) return 1; if (stbi_gif_info_from_file(f, x, y, comp)) + return 1; + if (stbi_bmp_info_from_file(f, x, y, comp)) + return 1; + if (stbi_psd_info_from_file(f, x, y, comp)) + return 1; + if (stbi_pic_info_from_file(f, x, y, comp)) return 1; - // @TODO: stbi_bmp_info_from_file - // @TODO: stbi_psd_info_from_file + #ifndef STBI_NO_DDS + if (stbi_dds_info_from_file(f, x, y, comp, NULL)) + return 1; + #endif #ifndef STBI_NO_HDR - // @TODO: stbi_hdr_info_from_file + if (stbi_hdr_info_from_file(f, x, y, comp)) + return 1; #endif // test tga last because it's a crappy test! if (stbi_tga_info_from_file(f, x, y, comp)) @@ -4520,11 +4561,20 @@ int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *c if (stbi_png_info_from_memory(buffer, len, x, y, comp)) return 1; if (stbi_gif_info_from_memory(buffer, len, x, y, comp)) + return 1; + if(stbi_bmp_info_from_memory(buffer, len, x, y, comp)) return 1; - // @TODO: stbi_bmp_info_from_memory - // @TODO: stbi_psd_info_from_memory + if(stbi_psd_info_from_memory(buffer, len, x, y, comp)) + return 1; + if(stbi_pic_info_from_memory(buffer, len, x, y, comp)) + return 1; + #ifndef STBI_NO_DDS + if (stbi_dds_info_from_memory(buffer, len, x, y, comp, NULL)) + return 1; + #endif #ifndef STBI_NO_HDR - // @TODO: stbi_hdr_info_from_memory + if(stbi_hdr_info_from_memory(buffer, len, x, y, comp)) + return 1; #endif // test tga last because it's a crappy test! if (stbi_tga_info_from_memory(buffer, len, x, y, comp)) @@ -4535,12 +4585,233 @@ int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *c // add in my DDS loading support #ifndef STBI_NO_DDS #include "stbi_DDS_c.h" -#endif +#endif + +static int bmp_info(stbi *s, int *x, int *y, int *comp) { + int hsz; + if (get8(s) != 'B' || get8(s) != 'M') return 0; + skip(s,12); + hsz = get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return 0; + if (hsz == 12) { + *x = get16le(s); + *y = get16le(s); + } else { + *x = get32le(s); + *y = get32le(s); + } + if (get16le(s) != 1) return 0; + *comp = get16le(s) / 8; + return 1; +} + +int stbi_bmp_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s,buffer, len); + return bmp_info( &s, x, y, comp ); +} + +#ifndef STBI_NO_STDIO +int stbi_bmp_info(char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_bmp_info_from_file( f, x, y, comp ); + fclose(f); + return res; +} + +int stbi_bmp_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = bmp_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +static int psd_info(stbi *s, int *x, int *y, int *comp) +{ + int channelCount; + if (get32(s) != 0x38425053) return 0; + if (get16(s) != 1) return 0; + skip(s, 6); + channelCount = get16(s); + if (channelCount < 0 || channelCount > 16) return 0; + *y = get32(s); + *x = get32(s); + if (get16(s) != 8) return 0; + if (get16(s) != 3) return 0; + *comp = 4; + return 1; +} + +int stbi_psd_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s,buffer, len); + return psd_info( &s, x, y, comp ); +} + +#ifndef STBI_NO_STDIO +int stbi_psd_info(char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_psd_info_from_file( f, x, y, comp ); + fclose(f); + return res; +} + +int stbi_psd_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = psd_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +static int pic_info(stbi *s, int *x, int *y, int *comp) +{ + skip(s, 92); + + *x = get16(s); + *y = get16(s); + if (at_eof(s)) return 0; + if ((1 << 28) / (*x) < (*y)) return 0; + + skip(s, 8); + + int act_comp=0,num_packets=0,chained; + pic_packet_t packets[10]; + + do { + pic_packet_t *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = get8(s); + packet->size = get8u(s); + packet->type = get8u(s); + packet->channel = get8u(s); + act_comp |= packet->channel; + + if (at_eof(s)) return 0; + if (packet->size != 8) return 0; + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} + +int stbi_pic_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s,buffer, len); + return pic_info( &s, x, y, comp ); +} + +#ifndef STBI_NO_STDIO +int stbi_pic_info(char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_pic_info_from_file( f, x, y, comp ); + fclose(f); + return res; +} + +int stbi_pic_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = pic_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +#ifndef STBI_NO_HDR +static int hdr_info(stbi *s, int *x, int *y, int *comp) +{ + char buffer[HDR_BUFLEN]; + char *token; + int valid = 0; + + if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) return 0; + + for(;;) { + token = hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return 0; + token = hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return 0; + token += 3; + *y = strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return 0; + token += 3; + *x = strtol(token, NULL, 10); + *comp = 3; + return 1; +} + +int stbi_hdr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s,buffer, len); + return hdr_info( &s, x, y, comp ); +} + +#ifndef STBI_NO_STDIO +int stbi_hdr_info(char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_hdr_info_from_file( f, x, y, comp ); + fclose(f); + return res; +} + +int stbi_hdr_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = hdr_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif +#endif #endif // STBI_HEADER_FILE_ONLY /* - revision history: + revision history: + 1.30 (2010-08-18) added stbi_info support for BMP,PSD,HDR,PIC by Martin Golini + 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) cast-to-uint8 to fix warnings diff --git a/src/helper/SOIL/stb_image.h b/src/helper/SOIL/stb_image.h index 85a22d292..6bd8b725a 100644 --- a/src/helper/SOIL/stb_image.h +++ b/src/helper/SOIL/stb_image.h @@ -210,7 +210,7 @@ typedef struct extern int stbi_register_loader(stbi_loader *loader); // define faster low-level operations (typically SIMD support) -#if STBI_SIMD +#ifdef STBI_SIMD typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize); // compute an integer IDCT on "input" // input[x] = data[x] * dequantize[x] @@ -232,7 +232,6 @@ extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); // TYPE-SPECIFIC ACCESS - #ifdef STBI_TYPE_SPECIFIC_FUNCTIONS // is it a jpeg? @@ -267,9 +266,14 @@ extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_bmp_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_bmp_test_file (FILE *f); extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_bmp_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_bmp_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a tga? @@ -277,9 +281,14 @@ extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_tga_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_tga_test_file (FILE *f); extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_tga_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_tga_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a psd? @@ -287,9 +296,14 @@ extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_psd_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_psd_test_file (FILE *f); extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_psd_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_psd_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it an hdr? @@ -297,9 +311,14 @@ extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_hdr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_hdr_test_file (FILE *f); extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_hdr_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_hdr_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a pic? @@ -307,9 +326,14 @@ extern int stbi_pic_test_memory (stbi_uc const *buffer, int len); extern stbi_uc *stbi_pic_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_pic_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + #ifndef STBI_NO_STDIO extern int stbi_pic_test_file (FILE *f); extern stbi_uc *stbi_pic_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_pic_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_pic_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // is it a gif? @@ -326,12 +350,12 @@ extern int stbi_gif_info (char const *filename, int *x, int extern int stbi_gif_info_from_file (FILE *f, int *x, int *y, int *comp); #endif -#endif//STBI_TYPE_SPECIFIC_FUNCTIONS - -#ifndef STBI_NO_DDS -#include "stbi_DDS.h" +#ifndef STBI_NO_DDS +#include "stbi_DDS.h" #endif +#endif//STBI_TYPE_SPECIFIC_FUNCTIONS + #ifdef __cplusplus } #endif @@ -340,3 +364,4 @@ extern int stbi_gif_info_from_file (FILE *f, int *x, int // //// end header file ///////////////////////////////////////////////////// #endif // STBI_INCLUDE_STB_IMAGE_H + diff --git a/src/helper/SOIL/stbi_DDS_c.h b/src/helper/SOIL/stbi_DDS_c.h index bf2f18d1e..eefbef451 100755 --- a/src/helper/SOIL/stbi_DDS_c.h +++ b/src/helper/SOIL/stbi_DDS_c.h @@ -338,9 +338,13 @@ int stbi_dds_info(char const *filename, int *x, int *y, int *comp, int *isco int stbi_dds_info_from_file(FILE *f, int *x, int *y, int *comp, int *iscompressed) { - stbi s; - start_file(&s, f); - return dds_get_info( &s, x, y, comp, iscompressed ); + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = dds_get_info(&s, x, y, comp, iscompressed); + fseek(f, n, SEEK_SET); + return res; } #endif diff --git a/src/helper/haikuttf/sophist.h b/src/helper/haikuttf/sophist.h index 0e8ac5933..3818b6b8e 100644 --- a/src/helper/haikuttf/sophist.h +++ b/src/helper/haikuttf/sophist.h @@ -1,4 +1,4 @@ -/* sophist.h - 0.2 - public domain - Sean Barrett 2010 +/* sophist.h - 0.3 - public domain - Sean Barrett 2010 ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net ** Sophist provides portable types; you typedef/#define them to your own names ** @@ -47,38 +47,40 @@ typedef unsigned short SOPHIST_uint16; typedef unsigned int SOPHIST_uint32; #endif -#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ - || (defined(__alpha) && defined(__DECC)) +#ifndef SOPHIST_NO_64 + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ + || (defined(__alpha) && defined(__DECC)) - typedef signed __int64 SOPHIST_int64; - typedef unsigned __int64 SOPHIST_uint64; - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) (x##i64) - #define SOPHIST_uint64_constant(x) (x##ui64) - #define SOPHIST_printf_format64 "I64" + typedef signed __int64 SOPHIST_int64; + typedef unsigned __int64 SOPHIST_uint64; + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##i64) + #define SOPHIST_uint64_constant(x) (x##ui64) + #define SOPHIST_printf_format64 "I64" -#elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) + #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) - typedef signed long SOPHIST_int64; - typedef unsigned long SOPHIST_uint64; + typedef signed long SOPHIST_int64; + typedef unsigned long SOPHIST_uint64; - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) - #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) - #define SOPHIST_printf_format64 "l" + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) + #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) + #define SOPHIST_printf_format64 "l" -#elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ - || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ - || defined(sgi) || defined (__sgi) || defined(__sgi__) \ - || defined(_CRAYC) + #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ + || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ + || defined(sgi) || defined (__sgi) || defined(__sgi__) \ + || defined(_CRAYC) - typedef signed long long SOPHIST_int64; - typedef unsigned long long SOPHIST_uint64; + typedef signed long long SOPHIST_int64; + typedef unsigned long long SOPHIST_uint64; - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) (x##LL) - #define SOPHIST_uint64_constant(x) (x##ULL) - #define SOPHIST_printf_format64 "ll" + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##LL) + #define SOPHIST_uint64_constant(x) (x##ULL) + #define SOPHIST_printf_format64 "ll" + #endif #endif #ifndef SOPHIST_has_64 @@ -142,7 +144,7 @@ SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); #define SOPHIST_endian SOPHIST_big_endian #endif -#endif // __INCLUDE_SOPHIST_H__ +#endif /* __INCLUDE_SOPHIST_H__ */ #ifdef SOPHIST_selftest #include @@ -154,6 +156,7 @@ int main(int argc, char **argv) SOPHIST_uint8 bytes[4]; SOPHIST_uint32 num; } x; + #if SOPHIST_has_64 char buffer[32]; sprintf(buffer, "%016" SOPHIST_printf_format64 "x", @@ -175,6 +178,10 @@ int main(int argc, char **argv) } fputs(fail ? "Failed.\n" : "Passed.\n", stdout); + + argc = argc; /* attempt to suppress unused variable warnings */ + argv = argv; + return 0; } #endif diff --git a/src/math/cmtrand.hpp b/src/math/cmtrand.hpp index 8e7411e17..ae48758b8 100755 --- a/src/math/cmtrand.hpp +++ b/src/math/cmtrand.hpp @@ -65,7 +65,7 @@ namespace EE { namespace Math { -class MTRand { +class EE_API MTRand { public: static const Uint32 M = 397; static const Int32 N = 624; diff --git a/src/math/math.hpp b/src/math/math.hpp index c6ce72273..d5fbc5b97 100755 --- a/src/math/math.hpp +++ b/src/math/math.hpp @@ -39,10 +39,17 @@ eeFloat EE_API Degrees( const eeFloat& Radians ); template T NextPowOfTwo( T Size ) { - T PowerOfTwo = 1; - while (PowerOfTwo < Size) - PowerOfTwo *= 2; - return PowerOfTwo; + T p = 1; + + while ( p < Size ) + p <<= 1; + + return p; +} + +template +T IsPow2( T v ) { + return ( ( v & ( v - 1 ) ) == 0 ); } template diff --git a/src/system/cobjectloader.hpp b/src/system/cobjectloader.hpp index b754bb2e1..98a91d03a 100644 --- a/src/system/cobjectloader.hpp +++ b/src/system/cobjectloader.hpp @@ -6,7 +6,7 @@ namespace EE { namespace System { -class cObjectLoader : cThread { +class EE_API cObjectLoader : cThread { public: typedef boost::function1 ObjLoadCallback; diff --git a/src/system/crc4.hpp b/src/system/crc4.hpp index ac7d32e5a..3814dc3d9 100755 --- a/src/system/crc4.hpp +++ b/src/system/crc4.hpp @@ -6,7 +6,7 @@ namespace EE { namespace System { /** @brief RC4 Encryption Class. For more information check Wikipedia: http://en.wikipedia.org/wiki/RC4. \n All the Decrypting functions call the Encrypting functions, there are there only for clarity, not really usefull. Use them as you wish. */ -class cRC4 { +class EE_API cRC4 { public: cRC4(); ~cRC4(); diff --git a/src/system/cresourceloader.cpp b/src/system/cresourceloader.cpp index 3575bc125..112945b80 100644 --- a/src/system/cresourceloader.cpp +++ b/src/system/cresourceloader.cpp @@ -145,5 +145,9 @@ void cResourceLoader::SetLoaded() { } } +eeFloat cResourceLoader::Progress() { + return ( (eeFloat)mObjsLoaded.size() / (eeFloat)( mObjs.size() + mObjsLoaded.size() ) ) * 100.f; +} + }} diff --git a/src/system/cresourceloader.hpp b/src/system/cresourceloader.hpp index 82bb74372..5e8fa04d4 100644 --- a/src/system/cresourceloader.hpp +++ b/src/system/cresourceloader.hpp @@ -8,7 +8,7 @@ namespace EE { namespace System { #define THREADS_AUTO (0xFFFFFFFF) -class cResourceLoader { +class EE_API cResourceLoader { public: typedef boost::function1 ResLoadCallback; @@ -32,6 +32,8 @@ class cResourceLoader { void Threaded( const bool& threaded ); bool Clear( const bool& ClearObjectsLoaded = true ); + + eeFloat Progress(); protected: bool mLoaded; bool mLoading; diff --git a/src/system/ctimeelapsed.cpp b/src/system/ctimeelapsed.cpp index 4a7ffa98c..c54ff440c 100755 --- a/src/system/ctimeelapsed.cpp +++ b/src/system/ctimeelapsed.cpp @@ -2,7 +2,7 @@ namespace EE { namespace System { -cTimeElapsed::cTimeElapsed() : mFirstCheck( getMicroseconds() ), mLastCheck( getMicroseconds() ), mElapsed(0) +cTimeElapsed::cTimeElapsed() : mFirstCheck( getMicroseconds() ), mLastCheck( getMicroseconds() ), mElapsed(0) { } @@ -11,14 +11,14 @@ cTimeElapsed::~cTimeElapsed() } eeDouble cTimeElapsed::Elapsed() { - mElapsed = ( getMicroseconds() - mLastCheck ) / (eeDouble)EE_CLOCKS_PER_SEC * 1000; - mLastCheck = getMicroseconds(); - + mElapsed = (eeDouble)( getMicroseconds() - mLastCheck ) / 1000.0; + mLastCheck = getMicroseconds(); + return mElapsed; } eeDouble cTimeElapsed::ElapsedSinceStart() { - return ( getMicroseconds() - mFirstCheck ) / (eeDouble)EE_CLOCKS_PER_SEC * 1000; + return (eeDouble)( getMicroseconds() - mFirstCheck ) / 1000.0; } void cTimeElapsed::Reset() { diff --git a/src/system/ctimeelapsed.hpp b/src/system/ctimeelapsed.hpp index 744c8691b..dec1be77f 100755 --- a/src/system/ctimeelapsed.hpp +++ b/src/system/ctimeelapsed.hpp @@ -13,17 +13,17 @@ class EE_API cTimeElapsed : private cTimer { ~cTimeElapsed(); /** Time elapsed between this call and the last call to Elapsed() */ - eeDouble Elapsed(); + eeDouble Elapsed(); /** Time elapsed between the last Reset ( First Reset is when the class is instantiated ) */ - eeDouble ElapsedSinceStart(); + eeDouble ElapsedSinceStart(); /** Restart the initial counter. ( set it as now ) */ - void Reset(); + void Reset(); protected: - eeUint mFirstCheck; - eeUint mLastCheck; - eeDouble mElapsed; + eeUint mFirstCheck; + eeUint mLastCheck; + eeDouble mElapsed; }; }} diff --git a/src/system/ctimer.cpp b/src/system/ctimer.cpp index e02330542..0ea228ea0 100755 --- a/src/system/ctimer.cpp +++ b/src/system/ctimer.cpp @@ -21,7 +21,7 @@ bool cTimer::setOption( const std::string key, const void * val ) { // Get the current process core mask DWORD procMask; DWORD sysMask; - + #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask); #else @@ -45,7 +45,7 @@ void cTimer::reset() { // Get the current process core mask DWORD procMask; DWORD sysMask; - + #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask); #else @@ -80,7 +80,7 @@ void cTimer::reset() { mLastTime = 0; mZeroClock = clock(); #else - zeroClock = clock(); + mZeroClock = clock(); gettimeofday(&start, NULL); #endif } @@ -177,20 +177,12 @@ unsigned long cTimer::getMicroseconds() { unsigned long cTimer::getMillisecondsCPU() { clock_t newClock = clock(); - #if EE_PLATFORM == EE_PLATFORM_WIN32 - return (unsigned long)( (eeFloat)( newClock - mZeroClock ) / ( (eeFloat)CLOCKS_PER_SEC / 1000.0 ) ); - #else - return (unsigned long)( (eeFloat)( newClock - zeroClock ) / ( (eeFloat)EE_CLOCKS_PER_SEC / 1000.0) ); - #endif + return (unsigned long)( (eeDouble)( newClock - mZeroClock ) / ( (eeDouble)CLOCKS_PER_SEC / 1000.0 ) ); } unsigned long cTimer::getMicrosecondsCPU() { clock_t newClock = clock(); - #if EE_PLATFORM == EE_PLATFORM_WIN32 - return (unsigned long)( (eeFloat)( newClock - mZeroClock ) / ( (eeFloat)CLOCKS_PER_SEC / 1000000.0 ) ); - #else - return (unsigned long)( (eeFloat)( newClock - zeroClock ) / ((eeFloat)EE_CLOCKS_PER_SEC / 1000000.0) ); - #endif + return (unsigned long)( (eeDouble)( newClock - mZeroClock ) / ( (eeDouble)CLOCKS_PER_SEC / 1000000.0 ) ); } }} diff --git a/src/system/ctimer.hpp b/src/system/ctimer.hpp index 2ac1868bf..6c707dc04 100644 --- a/src/system/ctimer.hpp +++ b/src/system/ctimer.hpp @@ -27,9 +27,8 @@ namespace EE { namespace System { class EE_API cTimer { private: + clock_t mZeroClock; #if EE_PLATFORM == EE_PLATFORM_WIN32 - clock_t mZeroClock; - unsigned long mStartTick; LONGLONG mLastTime; LARGE_INTEGER mStartTime; @@ -42,7 +41,6 @@ class EE_API cTimer { } #else struct timeval start; - clock_t zeroClock; #endif public: /** Timer constructor. MUST be called on same thread that calls getMilliseconds() */ diff --git a/src/test/ee.cpp b/src/test/ee.cpp index 299b9ec14..aac6c8932 100644 --- a/src/test/ee.cpp +++ b/src/test/ee.cpp @@ -1,11 +1,12 @@ #include "../ee.h" /** +@TODO Load Animated Sprites from Shape Groups. +@TODO Create a texture packer tool ( texture atlas ). @TODO Create a Vertex Buffer Object class ( with and without GL_ARB_vertex_buffer_object ). @TODO Add support for Frame Buffer Object and to switch rendering to FBO and Screen. @TODO Create a basic UI system ( add basic controls, add skinning support ). @TODO Support multitexturing. -@TODO Create a texture packer tool ( pack various textures into one texture ). @TODO Encapsulate SDL and OpenGL ( and remove unnecessary dependencies ). @TODO Add some Surface Grid class, to create special effects ( waved texture, and stuff like that ). @TODO Support color cursors ( not only black and white cursors, that really sucks ) - Imposible with SDL 1.2 @@ -190,6 +191,8 @@ class cEETest : private cThread { eeFloat mAxisY; Uint32 mFace; + + cTextureGroupLoader * mTGL; }; @@ -254,6 +257,8 @@ void cEETest::Init() { Scenes[1] = boost::bind( &cEETest::Screen2, this ); Scenes[2] = boost::bind( &cEETest::Screen3, this ); + mTGL = new cTextureGroupLoader( MyPath + "res/1.etg", true ); + InBuf.Start(); SetRandomSeed(); @@ -408,11 +413,11 @@ void cEETest::CmdSetPartsNum ( const std::vector < std::wstring >& params ) { if ( params.size() >= 2 ) { try { Int32 tInt = boost::lexical_cast( wstringTostring( params[1] ) ); - if ( tInt >= 0 && tInt <= 10000 ) { + if ( tInt >= 0 && tInt <= 100000 ) { PS[2].Create(WormHole, tInt, TN[5], EE->GetWidth() * 0.5f, EE->GetHeight() * 0.5f, 32, true); Con.PushText( L"Wormhole Particles Number Changed to: " + toWStr(tInt) ); } else - Con.PushText( L"Valid parameters are between 0 and 10000 (0 = no limit)." ); + Con.PushText( L"Valid parameters are between 0 and 100000 (0 = no limit)." ); } catch (boost::bad_lexical_cast&) { Con.PushText( L"Invalid Parameter. Expected int value from '" + params[1] + L"'." ); } @@ -1088,6 +1093,19 @@ void cEETest::Process() { else mFontLoader.Update(); + if ( !mTGL->IsLoaded() ) + mTGL->Update(); + else { + cShapeGroup * tSG = cShapeGroupManager::instance()->GetByName( "1.png" ); + + if ( NULL != tSG ) { + cShape * tS = tSG->GetByName( "rn01.png" ); + + if ( NULL != tS ) + tS->Draw( 320, 0 ); + } + } + if ( KM->IsKeyUp(KEY_F12) ) EE->TakeScreenshot( MyPath + "data/screenshots/" ); //After render and before Display EE->Display(); @@ -1108,6 +1126,8 @@ void cEETest::End() { cLog::instance()->Save(); + delete mTGL; + cEngine::DestroySingleton(); } @@ -1146,6 +1166,19 @@ void cEETest::Particles() { int main (int argc, char * argv []) { cEETest Test; Test.Process(); +/* + cTexturePacker tp; + std::string Path = "/home/downloads/files/temp/bnb/allin/"; + + if ( argc > 1 ) + Path = std::string( argv[1] ); + + tp.AddTexturesPath( Path ); + + tp.PackTextures( 256, 256 ); + + tp.Save( AppPath() + "res/1.png", EE_SAVE_TYPE_PNG ); +*/ return 0; } diff --git a/src/ui/cuibackground.hpp b/src/ui/cuibackground.hpp index 0f7c2e1aa..fbb3a3393 100644 --- a/src/ui/cuibackground.hpp +++ b/src/ui/cuibackground.hpp @@ -5,7 +5,7 @@ namespace EE { namespace UI { -class cUIBackground { +class EE_API cUIBackground { public: cUIBackground(); cUIBackground( const eeColorA& Color, const eeUint& Corners = 0, const EE_RENDERALPHAS& BlendMode = ALPHA_NORMAL ); diff --git a/src/ui/cuiborder.hpp b/src/ui/cuiborder.hpp index 477725f16..9019ef68d 100644 --- a/src/ui/cuiborder.hpp +++ b/src/ui/cuiborder.hpp @@ -5,7 +5,7 @@ namespace EE { namespace UI { -class cUIBorder { +class EE_API cUIBorder { public: cUIBorder(); cUIBorder( const cUIBorder& border ); diff --git a/src/utils/cinterpolation.hpp b/src/utils/cinterpolation.hpp index d0cb11265..2aa428fbd 100644 --- a/src/utils/cinterpolation.hpp +++ b/src/utils/cinterpolation.hpp @@ -17,7 +17,7 @@ class Point1d { typedef Point1d cPoint1df; /** @brief A interpolation movement manager, used for movement interpolations. */ -class cInterpolation { +class EE_API cInterpolation { public: cInterpolation(); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index bc9a696a2..24aec9dce 100755 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -16,9 +16,8 @@ #if EE_PLATFORM == EE_PLATFORM_WIN32 #include -#else - #include #endif +#include #if EE_PLATFORM == EE_PLATFORM_WIN32 #include @@ -32,14 +31,9 @@ namespace EE { namespace Utils { -bool FileExists(const std::string& filepath) { - std::fstream fs; - fs.open( filepath.c_str(), std::ios::in ); - if( fs.is_open() ) { - fs.close(); - return true; - } - return false; +bool FileExists( const std::string& Filepath ) { + struct stat st; + return ( stat( Filepath.c_str(), &st ) == 0 ); } Uint32 eeGetTicks() { @@ -197,13 +191,13 @@ std::vector FilesGetInPath( const std::string& path ) { } Uint32 FileSize( const std::string& Filepath ) { - std::ifstream f; - f.open(Filepath.c_str(), std::ios_base::binary | std::ios_base::in); - if (!f.good() || f.eof() || !f.is_open()) { return 0; } - f.seekg(0, std::ios_base::beg); - std::ifstream::pos_type begin_pos = f.tellg(); - f.seekg(0, std::ios_base::end); - return static_cast(f.tellg() - begin_pos); + struct stat st; + int res = stat( Filepath.c_str(), &st ); + + if ( 0 == res ) + return st.st_size; + + return 0; } eeDouble GetSystemTime() { @@ -337,6 +331,18 @@ std::string FileExtension( const std::string& filepath, const bool& lowerExt ) { return tstr; } +std::string FileRemoveExtension( const std::string& filepath ) { + return filepath.substr( 0, filepath.find_last_of(".") ); +} + +std::string FileNameFromPath( const std::string& filepath ) { + return filepath.substr( filepath.find_last_of("/\\") + 1 ); +} + +std::string FileRemoveFileName( const std::string& filepath ) { + return filepath.substr( 0, filepath.find_last_of("/\\") + 1 ); +} + eeInt GetNumCPUs() { eeInt nprocs = -1; @@ -389,4 +395,14 @@ bool FileWrite( const std::string& filepath, const std::vector& data ) { return FileWrite( filepath, reinterpret_cast ( &data[0] ), (Uint32)data.size() ); } +Uint32 FileGetModificationDate( const std::string& Filepath ) { + struct stat st; + int res = stat( Filepath.c_str(), &st ); + + if ( 0 == res ) + return st.st_mtime; + + return 0; +} + }} diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 631b1d64b..56279e178 100755 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -5,7 +5,7 @@ namespace EE { namespace Utils { /** @return True if the file exists */ - bool EE_API FileExists(const std::string& filepath); + bool EE_API FileExists( const std::string& Filepath ); /** @return The number of milliseconds since the EE++ library initialization. Note that this value wraps if the program runs for more than ~49 days. */ Uint32 EE_API eeGetTicks(); @@ -63,6 +63,15 @@ namespace EE { namespace Utils { */ std::string FileExtension( const std::string& filepath, const bool& lowerExt = true ); + /** @return The file name of a file path */ + std::string FileNameFromPath( const std::string& filepath ); + + /** @return Removes the file name from a path, and return the path. */ + std::string FileRemoveFileName( const std::string& filepath ); + + /** @return Removes the extension of a filepath */ + std::string FileRemoveExtension( const std::string& filepath ); + /** Write a file in binary mode and close it. */ bool FileWrite( const std::string& filepath, const Uint8* data, const Uint32& dataSize ); @@ -71,6 +80,9 @@ namespace EE { namespace Utils { /** @return The Number of CPUs of the system. */ eeInt GetNumCPUs(); + + /** @return The modification date of the file */ + Uint32 FileGetModificationDate( const std::string& Filepath ); } }