PDA

View Full Version : animated gif support



_diman
11-03-2012, 02:16 PM
Today I have been written a wrapper on giflib for loading gif-animated files
I think it looks more buty for resources.xml

<sprite name="Planet0001">
<image file="Planet0001.gif"/>
</sprite>

You must download giflib library and link it to your project
http://gnuwin32.sourceforge.net/packages/giflib.htm

The code only loading gif animated image and not do anything more for support resource format
It can be contain errors

PS to clanlib: it will be very nice, if your add animated formats support (gif, apng, or something also)
PSS I did not found support of any animated format

PSSS Sorry for my poor English




#include <gif_lib.h>

class GifLoader
{
GifFileType* mGifFile;

struct color
{
unsigned char b;
unsigned char g;
unsigned char r;
};


void loadExtensions()
{
int ext_code = APPLICATION_EXT_FUNC_CODE;
GifByteType* ext_buffer;

if (DGifGetExtension(mGifFile, &ext_code, &ext_buffer) == GIF_ERROR)
return;
while (DGifGetExtensionNext(mGifFile, &ext_buffer) == GIF_OK)
{
}
}
void loadScreenDesc()
{
if (DGifGetScreenDesc(mGifFile) == GIF_ERROR)
return;
}
static void setColor(GifColorType& Color, unsigned char r, unsigned char g, unsigned char b)
{
Color.Red = r;
Color.Green = g;
Color.Blue = b;
}
static ColorMapObject* getGlobalColorMap()
{
static ColorMapObject* global = nullptr;
if (global != nullptr)
return global;
global = new ColorMapObject;
global->ColorCount = 256;
global->BitsPerPixel = 8;
global->Colors = new GifColorType[global->ColorCount];

setColor(global->Colors[0], 0x00, 0x00, 0x00);
setColor(global->Colors[1], 0xff, 0xff, 0xff);
setColor(global->Colors[2], 0x00, 0xff, 0xff);
setColor(global->Colors[3], 0xff, 0x00, 0xff);
setColor(global->Colors[4], 0xff, 0xff, 0x00);
setColor(global->Colors[5], 0x00, 0x00, 0xff);
setColor(global->Colors[6], 0x00, 0xff, 0x00);
setColor(global->Colors[7], 0xff, 0x00, 0x00);
setColor(global->Colors[8], 0x80, 0x80, 0x80);
setColor(global->Colors[9], 0xc0, 0xc0, 0xc0);
setColor(global->Colors[10], 0x80, 0x00, 0x00);
setColor(global->Colors[11], 0x00, 0x80, 0x00);
setColor(global->Colors[12], 0x00, 0x00, 0x80);
setColor(global->Colors[13], 0x80, 0x80, 0x00);
setColor(global->Colors[14], 0x80, 0x00, 0x80);
setColor(global->Colors[15], 0x00, 0x80, 0x80);

unsigned char safecolor[] = {0x00, 0x33, 0x66, 0x99, 0xcc, 0xff};
for (size_t index = 0; index < 6; ++index)
for (size_t jindex = 0; jindex < 6; ++jindex)
for (size_t kindex = 0; kindex < 6; ++kindex)
setColor(global->Colors[16 + index * 36 + jindex * 6 + kindex], safecolor[index], safecolor[jindex], safecolor[kindex]);
}
public:

GifLoader():
mGifFile(nullptr)
{
}
GifLoader(CL_String& Path):
mGifFile(nullptr)
{
Open(Path);
}
~GifLoader()
{
if (IsOpened())
DGifCloseFile(mGifFile);
}

bool Open(CL_String& Path)
{
mGifFile = DGifOpenFileName(Path.c_str());
if (IsOpened() == false)
return false;
DGifSlurp(mGifFile);
return true;
}

bool IsOpened()
{
return mGifFile != nullptr;
}

size_t GetBpp()
{
if (IsOpened() == false)
return 0;
return 0;
}

size_t GetHeight()
{
if (IsOpened() == false)
return 0;
return (size_t)mGifFile->SHeight;
}

size_t GetWidth()
{
if (IsOpened() == false)
return 0;
return (size_t)mGifFile->SWidth;
}

size_t GetFrameCount()
{
if (IsOpened() == false)
return 0;
return mGifFile->ImageCount;
}

bool GetFrame(size_t Index, void* buffer)
{
if (IsOpened() == false)
return false;
if (Index >= (size_t)mGifFile->ImageCount)
return false;

SavedImage& image = mGifFile->SavedImages[Index];

ColorMapObject* color_map = mGifFile->SColorMap;
if (image.ImageDesc.ColorMap != nullptr)
color_map = image.ImageDesc.ColorMap;
if (color_map == nullptr)
color_map = getGlobalColorMap();

if (color_map->BitsPerPixel != 8)
throw CL_Exception(cl_format("Format is not supported"));

bool IsInterlace = (image.ImageDesc.Interlace & 0x40) == 0x40;

if (IsInterlace)
{
size_t width = GetWidth();
size_t height = GetHeight();
unsigned char* raster = image.RasterBits;

auto interlace = [&](size_t start, size_t delta)
{
color* current = nullptr;
for (size_t jindex = start; jindex < height; jindex += delta)
{
current = (color*)buffer + jindex * width;
for (size_t kindex = 0; kindex < width; ++kindex, ++current, ++raster)
{
unsigned char clr_index = *raster;
clr_index = clr_index % color_map->ColorCount;

GifColorType& clr = color_map->Colors[clr_index];
current->r = clr.Red;
current->g = clr.Green;
current->b = clr.Blue;
}
}
};

interlace(0, 8);
interlace(4, 8);
interlace(2, 4);
interlace(1, 2);

}
else
{
size_t pixels_count = GetHeight() * GetWidth();
color* current = (color*)buffer;
unsigned char* raster = mGifFile->SavedImages[Index].RasterBits;
for (size_t jindex = 0; jindex < pixels_count; ++jindex, ++current, ++raster)
{
unsigned char clr_index = *raster;
clr_index = clr_index % color_map->ColorCount;
GifColorType& clr = color_map->Colors[clr_index];
current->r = clr.Red;
current->g = clr.Green;
current->b = clr.Blue;
}
}

return true;
}

size_t GetFrameShowTime()
{
if (IsOpened() == false)
return 0;
return 0;
}

size_t GetLoopCount()
{
if (IsOpened() == false)
return 0;
return 0;
}
};

CL_Sprite LoadSprite(CL_GraphicContext& gc, const CL_String& resource_id, CL_ResourceManager* resources, const CL_ImageImportDescription& import_desc)
{
CL_Resource resource = resources->get_resource(resource_id);
if (resource.get_type() != "sprite")
throw CL_Exception(cl_format("Resource '%1' is not of type 'sprite' or 'sprite_description' or 'image'", resource_id));

CL_DomNode cur_node = resource.get_element().get_first_child();

CL_String image_name = cur_node.get_attributes().get_named_item("file").get_node_value();

CL_VirtualDirectory virtual_directory = resources->get_directory(resource);
CL_String filepath = virtual_directory.make_path_absolute(image_name);

GifLoader gif(filepath);
if (gif.IsOpened() == false)
throw CL_Exception(cl_format("Resource '%1' cannot be loaded", resource_id));
CL_SpriteDescription sprite_desc;

void* frame_data = ::malloc(gif.GetWidth() * gif.GetHeight() * 3);

size_t count = gif.GetFrameCount();
for (size_t Index = 0; Index < count; ++Index)
{
if (gif.GetFrame(Index, frame_data) == false)
continue;

CL_PixelBuffer buffer(gif.GetWidth(), gif.GetHeight(), CL_TextureFormat::cl_rgb8ui, frame_data, true);
sprite_desc.add_frame(buffer.copy());
sprite_desc.set_frame_delay(Index, ((double)gif.GetFrameShowTime()) / 100);
}

::free(frame_data);

return CL_Sprite(gc, sprite_desc);
}