Files
OpenSceneGraph/src/osgPlugins/gif/ReaderWriterGIF.cpp
Robert Osfield 83bf813e58 Moved the responsibility for finding file to load on to the ReaderWriter plugins,
instead of osgDB::Registry where it original lay.  This has been done to allow
fileName strings to be encode data rather than just file names, such as one
requires when using PagedLOD along with plugins for doing dynamic tesselation.
2003-12-08 11:24:43 +00:00

385 lines
11 KiB
C++

#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
/****************************************************************************
*
* Follows is code extracted from the simage library. Original Authors:
*
* Systems in Motion,
* <URL:http://www.sim.no>
*
* Peder Blekken <pederb@sim.no>
* Morten Eriksen <mortene@sim.no>
* Marius Bugge Monsen <mariusbu@sim.no>
*
* The original COPYING notice
*
* All files in this library are public domain, except simage_rgb.cpp which is
* Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
* very soon to hear if this source also can become public domain.
*
* Please send patches for bugs and new features to: <pederb@sim.no>.
*
* Peder Blekken
*
*
* Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
* Note, reference above to license of simage_rgb is not relevent to the OSG
* as the OSG does not use it. Also for patches, bugs and new features
* please send them direct to the OSG dev team rather than address above.
*
**********************************************************************/
/*!
GIF loader, using libungif
Based, in part, on source code found in libungif, gif2rgb.c
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
extern "C"
{
#include <gif_lib.h>
};
#define ERR_NO_ERROR 0
#define ERR_OPEN 1
#define ERR_READ 2
#define ERR_MEM 3
#define MY_GIF_DEBUG 1
static int giferror = ERR_NO_ERROR;
int
simage_gif_error(char * buffer, int buflen)
{
switch (giferror)
{
case ERR_OPEN:
strncpy(buffer, "GIF loader: Error opening file", buflen);
break;
case ERR_READ:
strncpy(buffer, "GIF loader: Error reading file", buflen);
break;
case ERR_MEM:
strncpy(buffer, "GIF loader: Out of memory error", buflen);
break;
}
return giferror;
}
int
simage_gif_identify(const char *,
const unsigned char *header,
int headerlen)
{
static unsigned char gifcmp[] = {'G', 'I', 'F'};
if (headerlen < 3) return 0;
if (memcmp((const void*)header,
(const void*)gifcmp, 3) == 0) return 1;
return 0;
}
static void
decode_row(GifFileType * giffile,
unsigned char * buffer,
unsigned char * rowdata,
int x, int y, int len,
int transparent)
{
GifColorType * cmentry;
ColorMapObject * colormap;
int colormapsize;
unsigned char col;
unsigned char * ptr;
y = giffile->SHeight - (y+1);
ptr = buffer + (giffile->SWidth * y + x) * 4;
colormap = (giffile->Image.ColorMap
? giffile->Image.ColorMap
: giffile->SColorMap);
colormapsize = colormap ? colormap->ColorCount : 255;
while (len--)
{
col = *rowdata++;
/* just in case */
if (col >= colormapsize) col = 0;
cmentry = colormap ? &colormap->Colors[col] : NULL;
if (cmentry)
{
*ptr++ = cmentry->Red;
*ptr++ = cmentry->Green;
*ptr++ = cmentry->Blue;
}
else
{
*ptr++ = col;
*ptr++ = col;
*ptr++ = col;
}
*ptr++ = (col == transparent ? 0x00 : 0xff);
}
}
unsigned char *
simage_gif_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{
int i, j, n, row, col, width, height, extcode;
unsigned char * rowdata;
unsigned char * buffer, * ptr;
unsigned char bg;
int transparent;
GifRecordType recordtype;
GifByteType * extension;
GifFileType * giffile;
GifColorType * bgcol;
/* The way an interlaced image should be read - offsets and jumps */
int interlacedoffset[] = { 0, 4, 2, 1 };
int interlacedjumps[] = { 8, 8, 4, 2 };
giffile = DGifOpenFileName(filename);
if (!giffile)
{
giferror = ERR_OPEN;
return NULL;
}
transparent = -1; /* no transparent color by default */
n = giffile->SHeight * giffile->SWidth;
buffer = new unsigned char [n * 4];
if (!buffer)
{
giferror = ERR_MEM;
return NULL;
}
rowdata = new unsigned char [giffile->SWidth];
if (!rowdata)
{
giferror = ERR_MEM;
delete [] buffer;
return NULL;
}
bg = giffile->SBackGroundColor;
if (giffile->SColorMap && bg < giffile->SColorMap->ColorCount)
{
bgcol = &giffile->SColorMap->Colors[bg];
}
else bgcol = NULL;
ptr = buffer;
for (i = 0; i < n; i++)
{
if (bgcol)
{
*ptr++ = bgcol->Red;
*ptr++ = bgcol->Green;
*ptr++ = bgcol->Blue;
*ptr++ = 0xff;
}
else
{
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0xff;
}
}
/* Scan the content of the GIF file and load the image(s) in: */
do
{
if (DGifGetRecordType(giffile, &recordtype) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
switch (recordtype)
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(giffile) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
/* subimage position in composite image */
row = giffile->Image.Top;
col = giffile->Image.Left;
width = giffile->Image.Width;
height = giffile->Image.Height;
if (giffile->Image.Left + giffile->Image.Width > giffile->SWidth ||
giffile->Image.Top + giffile->Image.Height > giffile->SHeight)
{
/* image is not confined to screen dimension */
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
if (giffile->Image.Interlace)
{
fprintf(stderr,"interlace\n");
/* Need to perform 4 passes on the images: */
for (i = 0; i < 4; i++)
{
for (j = row + interlacedoffset[i]; j < row + height;
j += interlacedjumps[i])
{
if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
else decode_row(giffile, buffer, rowdata, col, j, width, transparent);
}
}
}
else
{
for (i = 0; i < height; i++, row++)
{
if (DGifGetLine(giffile, rowdata, width) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
else decode_row(giffile, buffer, rowdata, col, row, width, transparent);
}
}
break;
case EXTENSION_RECORD_TYPE:
/* Skip any extension blocks in file: */
if (DGifGetExtension(giffile, &extcode, &extension) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
/* transparent test from the gimp gif-plugin. Open Source rulez! */
else if (extcode == 0xf9)
{
if (extension[0] >= 4 && extension[1] & 0x1) transparent = extension[4];
else transparent = -1;
}
while (extension != NULL)
{
if (DGifGetExtensionNext(giffile, &extension) == GIF_ERROR)
{
giferror = ERR_READ;
delete [] buffer;
delete [] rowdata;
return NULL;
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default: /* Should be trapped by DGifGetRecordType. */
break;
}
}
while (recordtype != TERMINATE_RECORD_TYPE);
delete [] rowdata;
*width_ret = giffile->SWidth;
*height_ret = giffile->SHeight;
*numComponents_ret = 4;
DGifCloseFile(giffile);
return buffer;
}
class ReaderWriterGIF : public osgDB::ReaderWriter
{
public:
virtual const char* className() { return "GIF Image Reader"; }
virtual bool acceptsExtension(const std::string& extension)
{
return osgDB::equalCaseInsensitive(extension,"gif");
}
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*)
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
std::string fileName = osgDB::findDataFile( file );
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
unsigned char *imageData = NULL;
int width_ret;
int height_ret;
int numComponents_ret;
imageData = simage_gif_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);
switch (giferror)
{
case ERR_OPEN:
return ReadResult("GIF loader: Error opening file");
case ERR_READ:
return ReadResult("GIF loader: Error reading file");
case ERR_MEM:
return ReadResult("GIF loader: Out of memory error");
}
if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED;
int s = width_ret;
int t = height_ret;
int r = 1;
int internalFormat = numComponents_ret;
unsigned int pixelFormat =
numComponents_ret == 1 ? GL_LUMINANCE :
numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
numComponents_ret == 3 ? GL_RGB :
numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
unsigned int dataType = GL_UNSIGNED_BYTE;
osg::Image* pOsgImage = new osg::Image;
pOsgImage->setFileName(fileName.c_str());
pOsgImage->setImage(s,t,r,
internalFormat,
pixelFormat,
dataType,
imageData,
osg::Image::USE_NEW_DELETE);
return pOsgImage;
}
};
// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterGIF> g_readerWriter_GIF_Proxy;