TexturePtr SpriteManager::getSpriteTexture(int id)
{
    if(id == 0)
        return g_graphics.getEmptyTexture();

    assert(id > 0 && id <= m_spritesCount);

    // load sprites on demand
    TexturePtr& sprite = m_sprites[id-1];
    if(!sprite)
        sprite = loadSpriteTexture(id);

    //TODO: release unused sprites textures after X seconds
    // to avoid massive texture allocations
    return sprite;
}
bool loadSpriteFromPNG (const char * file, struct spriteBank *sprites, int index)
{
	if (sprites->type<2) {
		char * error = joinStrings(file, "\n\nPNG files currently not supported in palette mode. Change to 32-bit mode and try again.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
	// Open the file	
	FILE * fp = fopen (file, "rb");
	if (fp == NULL) {
		char * error = joinStrings(file, "\n\nThe file can't be opened. I don't know why.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
	char tmp[10];
	size_t bytes_read = fread(tmp, 1, 8, fp);
	if (bytes_read != 8 && ferror (fp)) {
		fprintf(stderr, "Reading error in loadSpriteFromPNG.\n");
	}
    if (png_sig_cmp((png_byte *) tmp, 0, 8)) {
		fclose (fp);
		char * error = joinStrings(file, "\n\nIt doesn't appear to be a valid PNG image.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
    }
	
    png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
		fclose (fp);
		char * error = joinStrings(file, "\n\nError reading the file.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
		fclose (fp);
		char * error = joinStrings(file, "\n\nError reading the file.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
    }
	
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose (fp);
		char * error = joinStrings(file, "\n\nError readin the file");
		return errorBox ("Can't open PNG file", error);
    }
    png_init_io(png_ptr, fp);		// Tell libpng which file to read
    png_set_sig_bytes(png_ptr, 8);	// 8 bytes already read
	
	png_read_info(png_ptr, info_ptr);
	
	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type, compression_type, filter_method;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
	
    if (bit_depth < 8) png_set_packing(png_ptr);
	png_set_expand(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr);	
	if (bit_depth == 16) png_set_strip_16(png_ptr);

	png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
	
	png_read_update_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
		
	int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	
	unsigned char * row_pointers[height];
	unsigned char * data = new unsigned char [rowbytes*height];
	for (int i = 0; i<height; i++)
		row_pointers[i] = data + i*rowbytes;
	
	png_read_image(png_ptr, (png_byte **) row_pointers);
	png_read_end(png_ptr, NULL);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

	fclose (fp);
	if (sprites->sprites[index].data) delete sprites->sprites[index].data;
	
	sprites->sprites[index].data = data;
	sprites->sprites[index].width = width;
	sprites->sprites[index].height = height;
	
	int n, r, g, b;
	for (int x=0; x<width;x++) {
		for (int y=0; y<height; y++) {
			if (! sprites->sprites[index].data[4*width*y + x*4 + 3]) {
				n = r = g = b = 0;
				if (x>0 && sprites->sprites[index].data[4*width*y + (x-1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x-1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x-1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x-1)*4+2];
				}
				if (x<width-1 && sprites->sprites[index].data[4*width*y + (x+1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x+1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x+1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x+1)*4+2];
				}
				if (y>0 && sprites->sprites[index].data[4*width*(y-1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y-1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y-1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y-1) + x*4+2];
				}
				if (y<height-1 && sprites->sprites[index].data[4*width*(y+1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y+1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y+1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y+1) + x*4+2];
				}
				if (n) {
					r /= n;
					g /= n;
					b /= n;
					sprites->sprites[index].data[4*width*y + x*4]=r;
					sprites->sprites[index].data[4*width*y + x*4+1]=g;
					sprites->sprites[index].data[4*width*y + x*4+2]=b;
				}
			}
		}
	}
	
	loadSpriteTexture (sprites, index);
	return true;
}
bool loadSpriteFromTGA (const char * file, struct spriteBank *sprites, int index)
{
	palCol thePalette[256];

	// Open the file	
	FILE * fp = fopen (file, "rb");
	if (fp == NULL) {
		char * error = joinStrings(file, "\n\nThe file can't be opened. I don't know why.");
		errorBox ("Can't open TGA file", error);
		delete error;
		return false;
	}
		
	// Grab the header
	TGAHeader imageHeader;
	const char * errorBack;
	errorBack = readTGAHeader (imageHeader, fp, thePalette);
	if (errorBack) {
		fclose (fp);
		char * error = joinStrings(file, "\n\n", errorBack);
		errorBox ("Can't open TGA file", error);
		delete error;
		return false;
	}
	
	unsigned char *data;
		
	if (sprites->type < 2) {
		
		data = new unsigned char[imageHeader.height * imageHeader.width];
		if (! data) {
			fclose (fp);
			errorBox ("Can't create sprite", "Out of memory.");
			return false;		
		}
		
		unsigned char palSize = sprites->myPalette.total;
		unsigned char r,g,b;
		int c;
			
		for (int t2 = imageHeader.height-1; t2>=0; t2 --) {
			for (int t1 = 0; t1 < imageHeader.width; t1 ++) {
				if (! imageHeader.compressed) {
					grabRGB (fp, imageHeader.pixelDepth, r, g, b, thePalette);
				} else {
					grabRGBCompressed (fp, imageHeader.pixelDepth, r, g, b, thePalette);
				}
				if (sprites->type == 1)
					data[t2*imageHeader.width+t1] = findClosestPal (&sprites->myPalette, r, g, b);
				else {
					if ((c = findOrAddPal (&sprites->myPalette, r, g, b)) < 0) {
						fclose(fp);
						errorBox ("Can't create sprite", "The sprite bank palette doesn't have enough room left to add the colours. Change the palette mode to locked or 32-bit and try again.");
						sprites->myPalette.total = palSize;
						delete data;
						return false;
					}
					data[t2*imageHeader.width+t1] = c;
				}
			}
		}
	} else {
		data = new unsigned char[imageHeader.height * imageHeader.width * 4];
		if (! data) {
			fclose (fp);
			errorBox ("Can't create sprite", "Out of memory.");
			return false;		
		}
		
		unsigned char r,g,b,a;
		fprintf (stderr, "Compressed: %d (%d)\n", imageHeader.compressed, imageHeader.pixelDepth);
		
		for (int t2 = imageHeader.height-1; t2>=0; t2 --) {
			for (int t1 = 0; t1 < imageHeader.width; t1 ++) {
				if (! imageHeader.compressed) {
					grabRGBA (fp, imageHeader.pixelDepth, r, g, b, a, thePalette);
				} else {
					grabRGBACompressed (fp, imageHeader.pixelDepth, r, g, b, a, thePalette);
				}

				data[t2*imageHeader.width*4+t1*4] = r;
				data[t2*imageHeader.width*4+t1*4+1] = g;
				data[t2*imageHeader.width*4+t1*4+2] = b;
				data[t2*imageHeader.width*4+t1*4+3] = a;
			}
		}
	}
	fclose (fp);
	if (sprites->sprites[index].data) delete sprites->sprites[index].data;

	sprites->sprites[index].data = data;
	sprites->sprites[index].width = imageHeader.width;
	sprites->sprites[index].height = imageHeader.height;
	
	if (sprites->type>=2) {
	
	int n, r, g, b;
	int width = imageHeader.width;
	int height = imageHeader.height;
	for (int x=0; x<width;x++) {
		for (int y=0; y<height; y++) {
			if (! sprites->sprites[index].data[4*width*y + x*4 + 3]) {
				n = r = g = b = 0;
				if (x>0 && sprites->sprites[index].data[4*width*y + (x-1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x-1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x-1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x-1)*4+2];
				}
				if (x<width-1 && sprites->sprites[index].data[4*width*y + (x+1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x+1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x+1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x+1)*4+2];
				}
				if (y>0 && sprites->sprites[index].data[4*width*(y-1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y-1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y-1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y-1) + x*4+2];
				}
				if (y<height-1 && sprites->sprites[index].data[4*width*(y+1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y+1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y+1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y+1) + x*4+2];
				}
				if (n) {
					r /= n;
					g /= n;
					b /= n;
					sprites->sprites[index].data[4*width*y + x*4]=r;
					sprites->sprites[index].data[4*width*y + x*4+1]=g;
					sprites->sprites[index].data[4*width*y + x*4+2]=b;
				}
			}
		}
	}	
	}
	
	loadSpriteTexture (sprites, index);
	return true;
}