Files
eepp/src/graphics/ctexturegrouploader.cpp
2012-02-27 23:02:49 -03:00

491 lines
13 KiB
C++

#include "ctexturegrouploader.hpp"
#include "cshapegroup.hpp"
#include "cshapegroupmanager.hpp"
#include "ctexturepacker.hpp"
#include "cshapegroup.hpp"
#include "../system/ciostreamfile.hpp"
#include "../system/ciostreammemory.hpp"
namespace EE { namespace Graphics {
cTextureGroupLoader::cTextureGroupLoader() :
mThreaded(false),
mLoaded(false),
mAppPath( GetProcessPath() ),
mPack(NULL),
mSkipResourceLoad(false),
mIsLoading(false),
mShapeGroup(NULL)
{
}
cTextureGroupLoader::cTextureGroupLoader( const std::string& TextureGroupPath, const bool& Threaded ) :
mTextureGroupPath( TextureGroupPath ),
mThreaded( Threaded ),
mLoaded(false),
mAppPath( GetProcessPath() ),
mPack(NULL),
mSkipResourceLoad(false),
mIsLoading(false),
mShapeGroup(NULL)
{
Load();
}
cTextureGroupLoader::cTextureGroupLoader( const Uint8* Data, const Uint32& DataSize, const std::string& TextureGroupName, const bool& Threaded ) :
mTextureGroupPath( TextureGroupName ),
mThreaded( Threaded ),
mLoaded(false),
mAppPath( GetProcessPath() ),
mPack(NULL),
mSkipResourceLoad(false),
mIsLoading(false),
mShapeGroup(NULL)
{
LoadFromMemory( Data, DataSize, TextureGroupName );
}
cTextureGroupLoader::cTextureGroupLoader( cPack * Pack, const std::string& FilePackPath, const bool& Threaded ) :
mTextureGroupPath( FilePackPath ),
mThreaded( Threaded ),
mLoaded(false),
mAppPath( GetProcessPath() ),
mPack(NULL),
mSkipResourceLoad(false),
mIsLoading(false),
mShapeGroup(NULL)
{
LoadFromPack( Pack, FilePackPath );
}
cTextureGroupLoader::~cTextureGroupLoader()
{
}
void cTextureGroupLoader::Update() {
mRL.Update();
if ( mRL.IsLoaded() && !mLoaded )
CreateShapes();
}
void cTextureGroupLoader::LoadFromStream( cIOStream& IOS ) {
mRL.Threaded( mThreaded );
if ( IOS.IsOpen() ) {
IOS.Read( (char*)&mTexGrHdr, sizeof(sTextureGroupHdr) );
if ( mTexGrHdr.Magic == ( ( 'E' << 0 ) | ( 'E' << 8 ) | ( 'T' << 16 ) | ( 'G' << 24 ) ) ) {
for ( Uint32 i = 0; i < mTexGrHdr.TextureCount; i++ ) {
sTextureHdr tTextureHdr;
sTempTexGroup tTexGroup;
IOS.Read( (char*)&tTextureHdr, sizeof(sTextureHdr) );
tTexGroup.Texture = tTextureHdr;
tTexGroup.Shapes.resize( tTextureHdr.ShapeCount );
std::string name( &tTextureHdr.Name[0] );
std::string path( FileRemoveFileName( mTextureGroupPath ) + name );
//! Checks if the texture is already loaded
cTexture * tTex = cTextureFactory::instance()->GetByName( path );
if ( !mSkipResourceLoad && NULL == tTex ) {
if ( NULL != mPack ) {
mRL.Add( eeNew( cTextureLoader, ( mPack, path ) ) );
} else {
mRL.Add( eeNew( cTextureLoader, ( path ) ) );
}
}
IOS.Read( (char*)&tTexGroup.Shapes[0], sizeof(sShapeHdr) * tTextureHdr.ShapeCount );
mTempGroups.push_back( tTexGroup );
}
}
if ( !mSkipResourceLoad || ( !mSkipResourceLoad && 0 == mRL.Count() ) ) {
mIsLoading = true;
mRL.Load();
if ( !mThreaded || ( !mSkipResourceLoad && 0 == mRL.Count() ) )
CreateShapes();
}
}
}
void cTextureGroupLoader::Load( const std::string& TextureGroupPath ) {
if ( TextureGroupPath.size() )
mTextureGroupPath = TextureGroupPath;
if ( FileExists( mTextureGroupPath ) ) {
cIOStreamFile IOS( mTextureGroupPath, std::ios::in | std::ios::binary );
LoadFromStream( IOS );
} else if ( cPackManager::instance()->FallbackToPacks() ) {
std::string tgPath( mTextureGroupPath );
cPack * tPack = cPackManager::instance()->Exists( tgPath );
if ( NULL != tPack ) {
LoadFromPack( tPack, tgPath );
}
}
}
void cTextureGroupLoader::LoadFromPack( cPack * Pack, const std::string& FilePackPath ) {
if ( NULL != Pack && Pack->IsOpen() && -1 != Pack->Exists( FilePackPath ) ) {
mPack = Pack;
SafeDataPointer PData;
Pack->ExtractFileToMemory( FilePackPath, PData );
LoadFromMemory( reinterpret_cast<const Uint8*> ( PData.Data ), PData.DataSize, FilePackPath );
}
}
void cTextureGroupLoader::LoadFromMemory( const Uint8* Data, const Uint32& DataSize, const std::string& TextureGroupName ) {
if ( TextureGroupName.size() )
mTextureGroupPath = TextureGroupName;
cIOStreamMemory IOS( (const char*)Data, DataSize );
LoadFromStream( IOS );
}
cShapeGroup * cTextureGroupLoader::GetShapeGroup() const {
return mShapeGroup;
}
void cTextureGroupLoader::CreateShapes() {
mIsLoading = false;
bool IsAlreadyLoaded = false;
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 );
FilePathRemoveProcessPath( path );
cTexture * tTex = cTextureFactory::instance()->GetByName( path );
if ( NULL != tTex )
mTexuresLoaded.push_back( tTex );
// 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 ) {
if ( mTexGrHdr.Flags & HDR_TEXTURE_GROUP_REMOVE_EXTENSION )
name = FileRemoveExtension( name );
std::string etgpath = FileRemoveExtension( path ) + ".etg";
cShapeGroup * tShapeGroup = cShapeGroupManager::instance()->GetByName( name );
if ( NULL != tShapeGroup && tShapeGroup->Path() == etgpath ) {
mShapeGroup = tShapeGroup;
IsAlreadyLoaded = true;
} else {
mShapeGroup = eeNew( cShapeGroup, ( name ) );
mShapeGroup->Path( etgpath );
cShapeGroupManager::instance()->Add( mShapeGroup );
}
}
if ( NULL != tTex ) {
if ( !IsAlreadyLoaded ) {
for ( Int32 i = 0; i < tTexHdr->ShapeCount; i++ ) {
sShapeHdr * tSh = &tTexGroup->Shapes[i];
std::string ShapeName( &tSh->Name[0] );
if ( mTexGrHdr.Flags & HDR_TEXTURE_GROUP_REMOVE_EXTENSION )
ShapeName = FileRemoveExtension( ShapeName );
eeRecti tRect( tSh->X, tSh->Y, tSh->X + tSh->Width, tSh->Y + tSh->Height );
cShape * tShape = eeNew( cShape, ( tTex->Id(), tRect, (eeFloat)tSh->DestWidth, (eeFloat)tSh->DestHeight, tSh->OffsetX, tSh->OffsetY, ShapeName ) );
//if ( tSh->Flags & HDR_SHAPE_FLAG_FLIPED )
// Should rotate the shape, but.. shape rotation is not stored.
mShapeGroup->Add( tShape );
}
}
} else {
cLog::instance()->Write( "cTextureGroupLoader::CreateShapes: Failed to find texture group texture, it seems that is not loaded for some reason. Couldn't find: " + path );
eeASSERT( NULL != tTex );
return;
}
}
mLoaded = true;
}
bool cTextureGroupLoader::Threaded() const {
return mThreaded;
}
void cTextureGroupLoader::Threaded( const bool& threaded ) {
mThreaded = threaded;
}
const bool& cTextureGroupLoader::IsLoaded() const {
return mLoaded;
}
const bool& cTextureGroupLoader::IsLoading() const {
return mIsLoading;
}
cTexture * cTextureGroupLoader::GetTexture( const Uint32& texnum ) const {
eeASSERT( texnum < mTexuresLoaded.size() );
return mTexuresLoaded[ texnum ];
}
Uint32 cTextureGroupLoader::GetTexturesLoadedCount() {
return mTexuresLoaded.size();
}
bool cTextureGroupLoader::UpdateTextureAtlas() {
if ( NULL == mShapeGroup || !mTextureGroupPath.size() )
return false;
//! Update the data of the shape groups
for ( Uint32 z = 0; z < mTempGroups.size(); z++ ) {
sTempTexGroup * tTexGroup = &mTempGroups[z];
sTextureHdr * tTexHdr = &tTexGroup->Texture;
for ( Int32 i = 0; i < tTexHdr->ShapeCount; i++ ) {
sShapeHdr * tSh = &tTexGroup->Shapes[i];
cShape * tShape = mShapeGroup->GetById( tSh->ResourceID );
if ( NULL != tShape ) {
tSh->OffsetX = tShape->OffsetX();
tSh->OffsetY = tShape->OffsetY();
tSh->DestWidth = (Int32)tShape->DestWidth();
tSh->DestHeight = (Int32)tShape->DestHeight();
}
}
}
cIOStreamFile fs( mTextureGroupPath, std::ios::out | std::ios::binary );
if ( fs.IsOpen() ) {
fs.Write( reinterpret_cast<char*> (&mTexGrHdr), sizeof(sTextureGroupHdr) );
for ( Uint32 z = 0; z < mTempGroups.size(); z++ ) {
sTempTexGroup * tTexGroup = &mTempGroups[z];
sTextureHdr * tTexHdr = &tTexGroup->Texture;
fs.Write( reinterpret_cast<char*> ( tTexHdr ), sizeof(sTextureHdr) );
fs.Write( reinterpret_cast<char*> ( &tTexGroup->Shapes[0] ), sizeof(sShapeHdr) * (std::streamsize)tTexGroup->Shapes.size() );
}
return true;
}
return false;
}
static bool IsImage( std::string path ) {
if ( FileSize( path ) ) {
std::string File = path.substr( path.find_last_of("/\\") + 1 );
std::string Ext = File.substr( File.find_last_of(".") + 1 );
toLower( Ext );
if ( Ext == "png" ||
Ext == "tga" ||
Ext == "bmp" ||
Ext == "jpg" ||
Ext == "gif" ||
Ext == "jpeg" ||
Ext == "dds" ||
Ext == "psd" ||
Ext == "hdr" ||
Ext == "pic"
) {
return true;
} else {
int x,y,c;
int res = stbi_info( path.c_str(), &x, &y, &c );
if ( res )
return true;
}
}
return false;
}
bool cTextureGroupLoader::UpdateTextureAtlas( std::string TextureAtlasPath, std::string ImagesPath ) {
if ( !TextureAtlasPath.size() || !ImagesPath.size() || !FileExists( TextureAtlasPath ) || !IsDirectory( ImagesPath ) )
return false;
mSkipResourceLoad = true;
Load( TextureAtlasPath );
mSkipResourceLoad = false;
if ( !mTempGroups.size() )
return false;
Int32 x, y, c;
Int32 NeedUpdate = 0;
DirPathAddSlashAtEnd( ImagesPath );
Uint32 z;
Uint32 totalShapes = 0;
for ( z = 0; z < mTempGroups.size(); z++ )
totalShapes += mTempGroups[z].Texture.ShapeCount;
Uint32 totalImages = 0;
std::vector<std::string> PathFiles = FilesGetInPath( ImagesPath );
for ( z = 0; z < PathFiles.size(); z++ ) {
std::string realpath( ImagesPath + PathFiles[z] );
// Avoids reading file headers for known extensions
if ( IsImage( realpath ) )
totalImages++;
}
if ( totalShapes != totalImages ) {
NeedUpdate = 2;
} else {
for ( z = 0; z < mTempGroups.size(); z++ ) {
sTempTexGroup * tTexGroup = &mTempGroups[z];
sTextureHdr * tTexHdr = &tTexGroup->Texture;
if ( 2 != NeedUpdate ) {
for ( Int32 i = 0; i < tTexHdr->ShapeCount; i++ ) {
sShapeHdr * tSh = &tTexGroup->Shapes[i];
std::string path( ImagesPath + tSh->Name );
if ( FileSize( path ) ) {
if ( tSh->Date != FileGetModificationDate( path ) ) {
if ( stbi_info( path.c_str(), &x, &y, &c ) ) {
if ( ( !( tSh->Flags & HDR_SHAPE_FLAG_FLIPED ) && tSh->Width == x && tSh->Height == y ) || // If size or channels changed, the image need update
( ( tSh->Flags & HDR_SHAPE_FLAG_FLIPED ) && tSh->Width == y && tSh->Height == x ) ||
tSh->Channels != c
)
{
NeedUpdate = 1; // Only update the image with the newest one
} else {
NeedUpdate = 2; // The image change it, recreate all
break;
}
} else {
NeedUpdate = 2; // Something is wrong on the image
break;
}
}
} else {
NeedUpdate = 2; // Need recreation of the whole texture atlas, some image where deleted.
break;
}
}
} else {
break;
}
}
}
if ( NeedUpdate ) {
std::string tapath( FileRemoveExtension( TextureAtlasPath ) + "." + SaveTypeToExtension( mTexGrHdr.Format ) );
if ( 2 == NeedUpdate ) {
cTexturePacker tp( mTexGrHdr.Width, mTexGrHdr.Height, 0 != ( mTexGrHdr.Flags & HDR_TEXTURE_GROUP_POW_OF_TWO ), mTexGrHdr.PixelBorder, mTexGrHdr.Flags & HDR_TEXTURE_GROUP_ALLOW_FLIPPING );
tp.AddTexturesPath( ImagesPath );
tp.PackTextures();
tp.Save( tapath, (EE_SAVE_TYPE)mTexGrHdr.Format );
} else if ( 1 == NeedUpdate ) {
std::string etgpath = FileRemoveExtension( tapath ) + ".etg";
cIOStreamFile fs( etgpath , std::ios::out | std::ios::binary );
if ( !fs.IsOpen() )
return false;
fs.Write( reinterpret_cast<const char*> (&mTexGrHdr), sizeof(sTextureGroupHdr) );
for ( Uint32 z = 0; z < mTempGroups.size(); z++ ) {
if ( z != 0 ) {
tapath = FileRemoveExtension( TextureAtlasPath ) + "_ch" + toStr( z ) + "." + SaveTypeToExtension( mTexGrHdr.Format );
}
unsigned char * imgPtr = stbi_load( tapath.c_str(), &x, &y, &c, 0 );
if ( NULL != imgPtr ) {
cImage Img( imgPtr, x, y, c );
Img.AvoidFreeImage( true );
sTempTexGroup * tTexGroup = &mTempGroups[z];
sTextureHdr * tTexHdr = &tTexGroup->Texture;
fs.Write( reinterpret_cast<const char*> (tTexHdr), sizeof(sTextureHdr) );
for ( Int32 i = 0; i < tTexHdr->ShapeCount; i++ ) {
sShapeHdr * tSh = &tTexGroup->Shapes[i];
std::string imgcopypath( ImagesPath + tSh->Name );
Uint32 ModifDate = FileGetModificationDate( imgcopypath );
if ( tSh->Date != ModifDate ) {
tSh->Date = ModifDate; // Update the shape hdr
unsigned char * imgCopyPtr = stbi_load( imgcopypath.c_str(), &x, &y, &c, 0 );
if ( NULL != imgCopyPtr ) {
cImage ImgCopy( imgCopyPtr, x, y, c );
ImgCopy.AvoidFreeImage( true );
Img.CopyImage( &ImgCopy, tSh->X, tSh->Y ); // Update the image into the texture atlas
if ( imgCopyPtr )
free( imgCopyPtr );
} else
break;
}
}
fs.Write( reinterpret_cast<const char*> (&tTexGroup->Shapes[0]), sizeof(sShapeHdr) * tTexHdr->ShapeCount );
Img.SaveToFile( tapath, (EE_SAVE_TYPE)mTexGrHdr.Format );
if ( imgPtr )
free( imgPtr );
}
else
return false; // fatal error
}
}
}
return true;
}
std::string cTextureGroupLoader::AppPath() const {
return mAppPath;
}
}}