Skip to content

Commit

Permalink
Added animated gif support.
Browse files Browse the repository at this point in the history
  • Loading branch information
SpartanJ committed Nov 24, 2024
1 parent d1e5c64 commit 82494cc
Show file tree
Hide file tree
Showing 12 changed files with 370 additions and 109 deletions.
41 changes: 40 additions & 1 deletion include/eepp/graphics/image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ namespace EE { namespace Graphics {
/** @brief A simple image class to manipulate them. */
class EE_API Image {
public:
enum class Format {
Unknown = 0,
JPEG = 1,
PNG = 2,
BMP = 3,
GIF = 4,
TGA = 5,
PSD = 6,
PIC = 7,
PNM = 8,
DDS = 9,
PVR = 10,
PKM = 11,
HDR = 12,
QOI = 13,
SVG = 14,
};

/** @enum PixelFormat Format Pixel formats to write into a texture image. */
enum PixelFormat {
PIXEL_FORMAT_RED,
Expand Down Expand Up @@ -89,6 +107,9 @@ class EE_API Image {
Uint32 mJpegSaveQuality;
};

/* @return an array of images and the delay of the first frame */
static std::pair<std::vector<Image>, int> loadGif( IOStream& stream );

/** @return The File Extension of a Save Type */
static std::string saveTypeToExtension( const Int32& Format );

Expand Down Expand Up @@ -130,6 +151,22 @@ class EE_API Image {
*/
static bool isImage( const std::string& path );

/** @return True if the file is a valid image ( reads the file header to know if the file is an
* image file format supported )
* @param path the image path
*/
static bool isImage( const unsigned char* data, const size_t& dataSize );

/** @return The image format if valid
* @param path the image path
*/
static Image::Format getFormat( const std::string& path );

/** @return The image format if valid
* @param path the image path
*/
static Image::Format getFormat( const unsigned char* data, const size_t& dataSize );

/** @return If the path or file name has a supported image file extension
* @param path the image path or file name
*/
Expand Down Expand Up @@ -248,6 +285,8 @@ class EE_API Image {
/** @return A pointer to the first pixel of the image. */
virtual const Uint8* getPixelsPtr();

virtual const Uint8* getPixelsPtr() const;

/** Return the pointer to the array containing the image */
Uint8* getPixels() const;

Expand Down Expand Up @@ -279,7 +318,7 @@ class EE_API Image {
Sizei getSize();

/** Save the Image to a new File in a specific format */
virtual bool saveToFile( const std::string& filepath, const SaveType& Format );
virtual bool saveToFile( const std::string& filepath, const SaveType& Format ) const;

/** Create an Alpha mask from a Color */
virtual void createMaskFromColor( const Color& ColorKey, Uint8 Alpha );
Expand Down
39 changes: 31 additions & 8 deletions include/eepp/graphics/sprite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class EE_API Sprite : public Drawable {
SPRITE_EVENT_LAST_FRAME,
SPRITE_EVENT_FIRST_FRAME,
SPRITE_EVENT_END_ANIM_TO,
SPRITE_EVENT_NEW_FRAME,
SPRITE_EVENT_USER // User vents
};

Expand All @@ -36,6 +37,8 @@ class EE_API Sprite : public Drawable {
const Vector2i& offset = Vector2i( 0, 0 ),
const Rect& TexSector = Rect( 0, 0, 0, 0 ) );

static Sprite* fromGif( IOStream& gif );

/** Instanciate an empty sprite */
Sprite();

Expand Down Expand Up @@ -366,10 +369,15 @@ class EE_API Sprite : public Drawable {
void animToFrameAndStop( Uint32 GoTo );

/** Set the sprite events callback */
void setEventsCallback( const SpriteCallback& Cb, void* UserData = NULL );
void setEventsCallback( const SpriteCallback& Cb, void* UserData = nullptr );

/** Push a new event callback.
* @return The Callback Id
*/
Uint32 pushEventsCallback( const SpriteCallback& cb, void* UserData = nullptr );

/** Removes the current callback */
void clearCallback();
/** Pop the event callback id indicated. */
bool popEventsCallback( const Uint32& callbackId );

/** Creates a copy of the current sprite and returns it */
Sprite clone();
Expand All @@ -383,20 +391,31 @@ class EE_API Sprite : public Drawable {
/** Fire a User Event in the sprite */
void fireEvent( const Uint32& Event );

Sprite& setAsTextureRegionOwner( bool set );

bool isTextureRegionOwner() const;

Sprite& setAsTextureOwner( bool set );

bool isTextureOwner() const;

protected:
enum SpriteFlags {
SPRITE_FLAG_AUTO_ANIM = ( 1 << 0 ),
SPRITE_FLAG_REVERSE_ANIM = ( 1 << 1 ),
SPRITE_FLAG_ANIM_PAUSED = ( 1 << 2 ),
SPRITE_FLAG_ANIM_TO_FRAME_AND_STOP = ( 1 << 3 ),
SPRITE_FLAG_EVENTS_ENABLED = ( 1 << 4 )
SPRITE_FLAG_EVENTS_ENABLED = ( 1 << 4 ),
SPRITE_FLAG_TEXTURE_OWNER = ( 1 << 5 ),
SPRITE_FLAG_TEXTURE_REGION_OWNER = ( 1 << 6 ),
};

Uint32 mFlags{ SPRITE_FLAG_AUTO_ANIM | SPRITE_FLAG_EVENTS_ENABLED };
OriginPoint mOrigin{ OriginPoint::OriginCenter };
Float mRotation{ 0.f };
Vector2f mScale{ 1.f, 1.f };
Float mAnimSpeed{ 16.f };
Uint32 mNumCallBacks{ 0 };

Color* mVertexColors{ nullptr };

Expand All @@ -412,11 +431,13 @@ class EE_API Sprite : public Drawable {
unsigned int mSubFrames{ 1 };
unsigned int mAnimTo{ 0 };

SpriteCallback mCb;
void* mUserData{ nullptr };
struct SpriteCbData {
SpriteCallback cb;
void* userData{ nullptr };
};
UnorderedMap<Uint32, SpriteCbData> mCallbacks;

class Frame {
public:
struct Frame {
std::vector<TextureRegion*> Spr;
};
std::vector<Frame> mFrames;
Expand All @@ -425,6 +446,8 @@ class EE_API Sprite : public Drawable {

void clearFrame();

void cleanUpResources();

unsigned int getFrame( const unsigned int& FrameNum );

unsigned int getSubFrame( const unsigned int& SubFrame );
Expand Down
3 changes: 3 additions & 0 deletions include/eepp/graphics/texturefactory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ class EE_API TextureFactory : protected Mutex {
/** Determine if the TextureId passed exists */
bool existsId( const Uint32& TexId );

/** Determine if the TextureId passed exists */
bool exists( const Texture* tex );

/** @return A pointer to the Texture */
Texture* getTexture( const Uint32& TexId );

Expand Down
2 changes: 2 additions & 0 deletions include/eepp/ui/uiimage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class EE_API UIImage : public UIWidget {
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex = 0 ) const;

virtual void scheduledUpdate( const Time& time );

virtual std::vector<PropertyId> getPropertiesImplemented() const;

const UIScaleType& getScaleType() const;
Expand Down
61 changes: 60 additions & 1 deletion src/eepp/graphics/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,25 @@ bool Image::isImage( const std::string& path ) {
return STBI_unknown != stbi_test( path.c_str() ) || svg_test( path );
}

bool Image::isImage( const unsigned char* data, const size_t& dataSize ) {
return STBI_unknown != stbi_test_from_memory( data, dataSize ) ||
svg_test_from_memory( data, dataSize );
}

Image::Format Image::getFormat( const std::string& path ) {
auto format = stbi_test( path.c_str() );
if ( format == STBI_unknown )
return svg_test( path ) ? Image::Format::SVG : Image::Format::Unknown;
return static_cast<Image::Format>( format );
}

Image::Format Image::getFormat( const unsigned char* data, const size_t& dataSize ) {
auto format = stbi_test_from_memory( data, dataSize );
if ( format == STBI_unknown )
return svg_test_from_memory( data, dataSize ) ? Image::Format::SVG : Image::Format::Unknown;
return static_cast<Image::Format>( format );
}

bool Image::isImageExtension( const std::string& path ) {
const std::string ext( FileSystem::fileExtension( path ) );
return ( ext == "png" || ext == "tga" || ext == "bmp" || ext == "jpg" || ext == "gif" ||
Expand Down Expand Up @@ -670,6 +689,10 @@ const Uint8* Image::getPixelsPtr() {
return reinterpret_cast<const Uint8*>( &mPixels[0] );
}

const Uint8* Image::getPixelsPtr() const {
return reinterpret_cast<const Uint8*>( &mPixels[0] );
}

Color Image::getPixel( const unsigned int& x, const unsigned int& y ) {
eeASSERT( !( mPixels == NULL || x > mWidth || y > mHeight ) );
Color dst;
Expand Down Expand Up @@ -747,7 +770,7 @@ unsigned int Image::getChannels() const {
return mChannels;
}

bool Image::saveToFile( const std::string& filepath, const SaveType& Format ) {
bool Image::saveToFile( const std::string& filepath, const SaveType& Format ) const {
bool Res = false;

std::string fpath( FileSystem::fileRemoveFileName( filepath ) );
Expand Down Expand Up @@ -1000,4 +1023,40 @@ const Image::FormatConfiguration& Image::getImageFormatConfiguration() const {
return mFormatConfiguration;
}

std::pair<std::vector<Image>, int> Image::loadGif( IOStream& stream ) {
stbi_io_callbacks callbacks;
callbacks.read = &IOCb::read;
callbacks.skip = &IOCb::skip;
callbacks.eof = &IOCb::eof;
stream.seek( 0 );
auto type = stbi_test_from_callbacks( &callbacks, &stream );
if ( type != STBI_gif )
return {};
stream.seek( 0 );
std::vector<Image> gif;
ScopedBuffer buf( stream.getSize() );
stream.read( (char*)buf.get(), buf.size() );
int width, height, frames, comp;
int* delays = NULL;
unsigned char* data = stbi_load_gif_from_memory( buf.get(), buf.size(), &delays, &width,
&height, &frames, &comp, 0 );

if ( data == nullptr )
return {};

gif.reserve( frames );

unsigned char* start = data;
size_t frame_size = width * height * sizeof( unsigned char ) * comp;
for ( int i = 0; i < frames; ++i ) {
gif.emplace_back( (const Uint8*)start, width, height, comp );
start += frame_size;
}

auto delay = delays[0];
free( data );
free( delays );
return { std::move( gif ), delay };
}

}} // namespace EE::Graphics
Loading

0 comments on commit 82494cc

Please sign in to comment.