/*
	Simple Image Loading Library (loads PNG and JPEG images from files)
	Jason A. Petrasko, Public Domain
*/

#ifndef SILL_HEADER_FILE
#define SILL_HEADER_FILE

// formats for images
#define SIF_INVALID				0				// not a valid sill Image
#define SIF_GREYSCALE			8				// an 8 bit Greyscale image
#define SIF_GREYSCALE_ALPHA		16				// a 16 bit, Greyscale + Alpha channel image
#define SIF_GRAYSCALE			8				// an 8 bit Greyscale image
#define SIF_GRAYSCALE_ALPHA		16				// a 16 bit, Greyscale + Alpha channel image
#define SIF_COLOR				24				// a 24 bit, RGB channel image
#define SIF_COLOR_ALPHA			32				// a 32 bit, RGBA channel image

// 32 bytes on most systems
typedef struct _sillImage {
	int Format;					// Format of this image, see define above
	int Width, Height;			// Dimensions of this image
	unsigned char *Pixels;		// Pixels of this image, based on the format shown above
	char *Source;				// Name of the source file
	const char *Error;			// Set to null if no error, or supplies an error if one occured
	unsigned int UserFlags;		// User flags, nothing we care about
	unsigned int UniqueId;		// A unique id for this image, created when its made by the engine
} sillImage;

#ifdef BUILD_DLL

/* DLL export */

#define EXPORT __declspec(dllexport)
EXPORT sillImage *sillLoadFile(const char *src);						// load a file and return that image
EXPORT sillImage *sillBlank(int w, int h, int f);						// return a new blank (all 0s) image
EXPORT sillImage *sillDuplicate(sillImage *p);							// return a duplicate of the image
EXPORT int sillIsValid(sillImage *p);									// returns 1 if valid, or 0 otherwise
EXPORT void sillSize(sillImage *p, int nw, int nh);						// simple expand or crop, not a resample or anything
EXPORT void sillForceAlpha(sillImage *p);								// force an image to contain an alpha channel
EXPORT void sillForceGrey(sillImage *p);								// force an image to become greyscale
EXPORT void sillForceColor(sillImage *p);								// force an image to become color
EXPORT void sillAlphaByLuminance(sillImage *p, float pow);				// set alpha by luminance, use power given as: alpha = luminance ^ pow
EXPORT void sillFree(sillImage **p);									// free that image
EXPORT const char *sillSavePng(sillImage *p, const char *dst);			// save a png of the image, return error if failed or null on success

#else

/* Dynamic load code */

typedef struct _sillInterface {
	void *DllHandle;
	sillImage *(*LoadFile)(const char *src);						// load a file and return that image
	sillImage *(*Blank)(int w, int h, int f);						// return a new blank (all 0s) image
	sillImage *(*Duplicate)(sillImage *p);							// return a duplicate of the image
	int (*IsValid)(sillImage *p);									// returns 1 if valid, or 0 otherwise
	void (*Size)(sillImage *p, int nw, int nh);						// simple expand or crop, not a resample or anything
	void (*ForceAlpha)(sillImage *p);								// force an image to contain an alpha channel
	void (*ForceGrey)(sillImage *p);								// force an image to become greyscale
	void (*ForceColor)(sillImage *p);								// force an image to become color
	void (*AlphaByLuminance)(sillImage *p, float pow);				// set alpha by luminance, use power given as: alpha = luminance ^ pow
	void (*Free)(sillImage **p);									// free that image
	const char* (*SavePng)(sillImage *p, const char *dst);			// save a png of the image, return error if failed or null on success
} sillInterface;


#ifdef WIN32

#include <windows.h>
sillInterface* sillOpen(const char *fname) {
		sillInterface *ret = (sillInterface*)calloc(1, sizeof(sillInterface)); 
		ret->DllHandle = LoadLibrary(fname);
		if (!ret->DllHandle) return ret;
			ret->LoadFile = (sillImage* (*)(const char*))GetProcAddress((HMODULE)ret->DllHandle,"sillLoadFile");
			ret->Blank = (sillImage* (*)(int, int, int))GetProcAddress((HMODULE)ret->DllHandle,"sillBlank");
			ret->Duplicate = (sillImage* (*)(sillImage*))GetProcAddress((HMODULE)ret->DllHandle,"sillDuplicate");
			ret->IsValid = (int (*)(sillImage*))GetProcAddress((HMODULE)ret->DllHandle,"sillIsValid");
			ret->Size = (void (*)(sillImage*,int,int))GetProcAddress((HMODULE)ret->DllHandle,"sillSize");
			ret->ForceAlpha = (void (*)(sillImage*))GetProcAddress((HMODULE)ret->DllHandle,"sillForceAlpha");
			ret->ForceGrey = (void (*)(sillImage*))GetProcAddress((HMODULE)ret->DllHandle,"sillForceGrey");
			ret->ForceColor = (void (*)(sillImage*))GetProcAddress((HMODULE)ret->DllHandle,"sillForceColor");
			ret->AlphaByLuminance = (void (*)(sillImage*,float))GetProcAddress((HMODULE)ret->DllHandle,"sillAlphaByLuminance");
			ret->Free = (void (*)(sillImage**))GetProcAddress((HMODULE)ret->DllHandle,"sillFree");
			ret->SavePng = (const char* (*)(sillImage*,const char*))GetProcAddress((HMODULE)ret->DllHandle,"sillSavePng");
		return ret;				
		}
int sillOk(sillInterface *p) { return p->DllHandle != 0; }
void sillClose(sillInterface *p) { FreeLibrary((HMODULE)p->DllHandle); free(p); }
	
#else
	#include <dlfcn.h>

sillInterface* sillOpen(const char *fname) {
		sillInterface *ret = (sillInterface*)calloc(1, sizeof(sillInterface)); 
		ret->DllHandle = dlopen(fname,0);
		if (!ret->DllHandle) return ret;
			ret->LoadFile = (sillImage* (*)(const char*))dlsym(ret->DllHandle,"sillLoadFile");
			ret->Blank = (sillImage* (*)(int, int, int))dlsym(ret->DllHandle,"sillBlank");
			ret->Duplicate = (sillImage* (*)(sillImage*))dlsym(ret->DllHandle,"sillDuplicate");
			ret->IsValid = (int (*)(sillImage*))dlsym(ret->DllHandle,"sillIsValid");
			ret->Size = (void (*)(sillImage*,int,int))dlsym(ret->DllHandle,"sillSize");
			ret->ForceAlpha = (void (*)(sillImage*))dlsym(ret->DllHandle,"sillForceAlpha");
			ret->ForceGrey = (void (*)(sillImage*))dlsym(ret->DllHandle,"sillForceGrey");
			ret->ForceColor = (void (*)(sillImage*))dlsym(ret->DllHandle,"sillForceColor");
			ret->AlphaByLuminance = (void (*)(sillImage*,float))dlsym(ret->DllHandle,"sillAlphaByLuminance");
			ret->Free = (void (*)(sillImage**))dlsym(ret->DllHandle,"sillFree");
			ret->SavePng = (const char* (*)(sillImage*,const char*))dlsym(ret->DllHandle,"sillSavePng");
		return ret;				
		}
int sillOk(sillInterface *p) { return p->DllHandle != 0; }
void sillClose(sillInterface *p) { dlclose(p->DllHandle); free(p); }

#endif // win32/unix

#endif // build/dload


#endif // safety


