////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mdanks@cybermed.ucsd.edu
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "GemPixImageLoad.h"

#include "m_pd.h"

extern "C"
{
#ifdef __linux__ /* I still think that people should install libtiff 
                    by themselves, especially on linux  */
    #include <tiffio.h>
#else
    #include "tiff/libtiff/tiffio.h"
#endif
}

imageStruct *image2mem(const char *filename)
{
    TIFF *tif = TIFFOpen(filename, "r");
    if (tif == NULL)
    {
    	post("GEM: Cannot open image file: %s", filename);
    	return(NULL);
    }

	uint32 width, height;
	short bits, samps;
    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
	TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits);
	TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samps);
    
	int npixels = width * height;

	imageStruct *image_block = new imageStruct;
        
	image_block->xsize = width;
	image_block->ysize = height;
	image_block->type  = GL_UNSIGNED_BYTE;

	int knownFormat = 0;
	// Is it a gray8 image?
	if (bits == 8 && samps == 1)
	{
		image_block->csize = samps;
		image_block->format = GL_LUMINANCE;
		knownFormat = 1;
	}
	// Is it an RGB image?
	else if (bits == 8 && samps == 3)
	{
		image_block->csize = 4;
		image_block->format = GL_RGBA;
		knownFormat = 1;
	}
	// Is it an RGBA image?
	else if (bits == 8 && samps == 4)
	{
		image_block->csize = 4;
		image_block->format = GL_RGBA;
		knownFormat = 1;
	}

	// can we handle the raw data?
	if (knownFormat)
	{
	    unsigned char *buf = new unsigned char [TIFFScanlineSize(tif)];
	    if (buf == NULL)
		{
			error("GEM: can't allocate memory for scanline buffer: %s", filename);
		    TIFFClose(tif);
			delete image_block;
			return(NULL);
		}
    
		image_block->data = new unsigned char[npixels * image_block->csize];
		unsigned char *pixels = image_block->data;
	    for (uint32 row = 0; row < height; row++)
		{
			if (TIFFReadScanline(tif, buf, row, 0) < 0)
			{
			    error("GEM: bad data read on line: %d: %s", row, filename);
			    TIFFClose(tif);
				delete image_block;
				delete [] buf;
				return(NULL);
			}
			unsigned char *inp = buf;
			if (samps == 1)
			{
				for (uint32 i = 0; i < width; i++)
				{
    				*pixels++ = *inp++;			// Gray8
				}
			}
			else if (samps == 3)
			{
				for (uint32 i = 0; i < width; i++)
				{	
    				*pixels++ = inp[0];			// Red
    				*pixels++ = inp[1];			// Green
    				*pixels++ = inp[2];			// Blue
    				*pixels++ = 255;			// Alpha
					inp += 3;
				}
			}
			else
			{
				for (uint32 i = 0; i < width; i++)
				{					
    				*pixels++ = inp[0];			// Red
    				*pixels++ = inp[1];			// Green
    				*pixels++ = inp[2];			// Blue
    				*pixels++ = inp[3];			// Alpha
					inp += 4;
				}
			}
		}
		delete [] buf;
	}
	// nope, so use the automatic conversion
	else
	{
		char emsg[1024];
		TIFFRGBAImage img;
		if (TIFFRGBAImageBegin(&img, tif, 0, emsg) == 0)
		{
	        post("GEM: Error reading in file: %s : %s", filename, emsg);
			delete image_block;
	        TIFFClose(tif);
	        return(NULL);
		}

		uint32 *raster = (uint32 *) _TIFFmalloc(npixels * sizeof(uint32));
		if (raster == NULL)
		{
			error("GEM: Unable to allocate memory for image: %s", filename);
			TIFFClose(tif);
			delete image_block;
			return(NULL);
		}

		if (TIFFRGBAImageGet(&img, raster, width, height) == 0)
		{
			post("GEM: Error getting data in file: %s, %s", filename, emsg);
			_TIFFfree(raster);
			TIFFClose(tif);
			delete image_block;
			return(NULL);
		}

	    TIFFRGBAImageEnd(&img);

		image_block->csize = 4;
		image_block->format = GL_RGBA;
		image_block->data = new unsigned char[npixels * image_block->csize];
		unsigned char *pixels = image_block->data;

		// transfer everything over
		for (int i = 0; i < npixels; i++)
		{
			*pixels++ = (unsigned char)TIFFGetR(raster[i]);		// Red
			*pixels++ = (unsigned char)TIFFGetG(raster[i]);		// Green
			*pixels++ = (unsigned char)TIFFGetB(raster[i]);		// Blue
			*pixels++ = (unsigned char)TIFFGetA(raster[i]);		// Alpha
		}
        _TIFFfree(raster);
	}
	
    TIFFClose(tif);

    return(image_block);
}

