-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Source: Animated GIF
mcmarius edited this page May 4, 2022
·
4 revisions
A small class to display animated GIFs. This is a proof of concept; you'll probably don't just want to copy and paste the code. It makes use of stb_image.h, which SFML also uses to load images.
#ifndef __ANIMATEDGIF_H__
#define __ANIMATEDGIF_H__
#include <SFML/Graphics.hpp>
#include <vector>
#include <tuple>
class AnimatedGIF
{
public:
AnimatedGIF(const char* filename);
const sf::Vector2i& getSize(void);
void update(sf::Sprite& sprite);
private:
sf::Vector2i size;
sf::Clock clock;
sf::Time startTime;
sf::Time totalDelay;
std::vector<std::tuple<int, sf::Texture>> frames;
std::vector<std::tuple<int, sf::Texture>>::iterator frameIter;
};
#endif
#include "AnimatedGIF.h"
//#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_GIF
#include <stb/stb_image.h>
AnimatedGIF::AnimatedGIF(const char* filename)
{
FILE *f = stbi__fopen(filename, "rb");
stbi__context s;
stbi__start_file(&s, f);
int *delays = 0;
int z = 0, comp = 0;
void *pixels = stbi__load_gif_main(&s, &delays, &size.x, &size.y, &z, &comp, STBI_rgb_alpha);
sf::Image image;
int step = size.x * size.y * 4;
for (int i = 0; i < z; i++)
{
image.create(size.x, size.y, (const sf::Uint8*) pixels + step * i);
sf::Texture texture;
texture.loadFromImage(image);
frames.push_back(std::tuple<int, sf::Texture>(delays[i], texture));
}
frameIter = frames.begin();
stbi_image_free(pixels);
if(delays)
stbi_image_free(delays);
fclose(f);
totalDelay = sf::Time::Zero;
startTime = clock.getElapsedTime();
}
const sf::Vector2i&
AnimatedGIF::getSize()
{
return size;
}
void
AnimatedGIF::update(sf::Sprite& sprite)
{
sf::Time delay = sf::milliseconds(std::get<0>(*frameIter));
while (startTime + totalDelay + delay < clock.getElapsedTime())
{
frameIter++;
if (frameIter == frames.end()) frameIter = frames.begin();
totalDelay += delay;
delay = sf::milliseconds(std::get<0>(*frameIter));
}
sf::Texture &texture = std::get<1>(*frameIter);
sprite.setTexture(texture);
}
#include <iostream>
#include <SFML/Graphics.hpp>
#include "AnimatedGIF.h"
int main(int argc, char** argv)
{
if (argc < 2)
{
std::cerr << "No argument" << std::endl;
return 1;
}
AnimatedGIF gif(argv[1]);
sf::Vector2i size = gif.getSize();
sf::RenderWindow window(sf::VideoMode(size.x, size.y), "gifdemo");
window.setFramerateLimit(60);
sf::Sprite sprite;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
gif.update(sprite);
window.clear(sf::Color::Black); // draw the background so the gif does not leave trails from previous frames
window.draw(sprite);
window.display();
}
return EXIT_SUCCESS;
}