////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 RWS Inc, All Rights Reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as published by
// the Free Software Foundation
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef IMAGE_H
#define IMAGE_H
//////////////////////////////////////////////////////////////////////
//
//	IMAGE.H
//   
//	Created on 		4/20/95	MR 
// Implemented on 4/21/95	JW
// 05/08/95	JMI	Took out CDib dependency and added internal method
//						for loading BMPs.
//
//	05/10/95	JMI	Added prototype for conversion function Convert in
//						CPal that converts from current type to others.
//
//	05/10/95	JMI	Added member to store whether it's okay to free
//						the palette data (i.e., we allocated it in CPal).
//
//	09/26/95 BRH	Completely changed the CImage class to a new
//						version that is compatible with Jeff's Blit modules
//						and includes expandability for future image types.
//						This is the new standard image which each new image
//						type will be required to understand and be able to 
//						convert to/from.  This CImage will complete the missing
//						link between the app level image format and Jeff's
//						Blit library.  There is no CPalImage anymore, but the
//						more general CImage may have a valid CPal pointer or
//						NULL if there is no palette.
//
// 02/27/96 BRH	Changed the Convert functions from using DYNALINK
//						to the friend class CImageSpecialFunc which includes
//						ConvertTo, ConvertFrom, Load, Save, Alloc, and Delete.
//						It became necessary to load and save special formats
//						like fast sprite so that the images could be on the
//						disk in the final form used in the game rather than
//						loading bitmaps and converting them in the game code.
//						It was also necessary to add alloc/delete functions
//						so that special image types that may allocate structures
//						or classes associated with the pSpeical pointer could
//						be freed properly when the CImage destructor was called,
//						and similarly if someone wanted to create a new CImage
//						of a special type with a structure or class, the constructor
//						will call the special Alloc function to allocate the special
//						data associated with the pSpecial pointer.
//
// 04/30/96	BRH	Added some new fields to the header of the CImage, thus
//						invalidating the previous .IMG files but at this point they
//						weren't in wide use.  The Blit routines required a few
//						additional pieces of information so that they could avoid
//						recreating the buffer as they needed it.  I added 
//						lBufferWidth, lBufferHeight, lXPos, lYPos to accomodate 
//						the Blit functions.  This way a buffer that is larger
//						than the image can be created and the image can be
//						located at a specific position in that buffer. Note that
//						the whole buffer is not saved, just the image but the
//						size of the buffer is saved so that upon load, the buffer
//						can be recreated at its desired size.  
//						I also added ulDestinationType to accomodate image formats
//						that may be saved as one type but are converted to another
//						type once they are loaded.  For example, if you are using
//						sprites and there is no save funciton for sprites, you can
//						save the file with BMP8 type and a destination type of
//						FAST_SPRITE so that when the file is loaded, it is
//						read as a BMP8 format but automatically converted to
//						the fast sprite type.  Then to avoid debugging problems
//						when the CImage header is changed, I added a version number
//						as a #define and write that to the file.  Then when a .IMG file
//						is loaded, the version number is checked with the current
//						version of CImage and if they are different it will return
//						an error.
//
//	10/21/96 BRH	Added file type and version to identify palette files.
//
//	10/30/96	JMI	Pulled CPal stuff out of here and put it into pal.h.
//						Pulled enum stuff out of imagetyp.h and put it here.
//						Removed #include of imagtyp.h.
//						Added #include of pal.h.
//						Attempted to reword comment summary to reflect these
//						changes.
//						Note: I'm not positive but I think the references to
//						imageafp.h are out of date.
//
//	10/30/96	JMI	Changed:
//						Old label:		New label:
//						=========		=========
//						CNFile			RFile
//						CImage			RImage
//						CPal				RPal
//						uint32_t ulType	RImage::Type ulType
//						
//						Added a using directive to IMAGELINKLATE.
//
//	10/31/96	JMI	Changed all members to be preceded by m_ (e.g., sDepth
//						m_sDepth).  Changed all position members (i.e., lWidth,
//						lHeight, lBufferWidth, lBufferHeight, lXPos, & lYPos) to
//						be shorts (i.e., m_sWidth, m_sHeight, m_sBufferWidth,
//						m_sBufferHeight, m_sXPos, m_sYPos) and functions associated
//						with these members reflect this change (e.g., long GetWidth()
//						is now short GetWidth()).  Changed ulType to	m_type and 
//						ulDestinationType to m_typeDestination.  Increased file
//						version to 5 since members converted to short will affect
//						the file format.
//
//	11/06/96 MJR	Got rid of "using" syntax in IMAGELINKLATE macro
//						because that didn't work with CodeWarrior on the mac.
//
//	11/27/96 BRH	Changed names of the buffer and image width around
//						to make the usage more clear and to make sure that
//						code using the previous method would not quit working
//						due to this change.  Previously the widht and height
//						referred to the visible picture which may be stored
//						in a larger buffer.  The BufferWidth and BufferHeight
//						referred to the size of the memory in which the picture
//						was being stored.  Now we will change the width and height
//						to mean the entire memory area and the size of the picture
//						will be referred to by WinWidth and WinHeight.  I am 
//						rearranging the order of the variables in the class so
//						that I won't have to change the version of the file
//						format and I will also change the order that these values
//						are being written and read from the files so that old
//						image files will continue to work.
//
//	12/18/96 BRH	Added overloaded versions of LoadDib and SaveDib that
//						take an RFile* and can load or save to that rather than
//						just the filename versions.  This was first used
//						in the resource manager but is also otherwise
//						generally useful.
//
//	12/18/96	JMI	Added TOUCH macros to aid in dynamic linking.  See comment
//						there for more detail.
//
//	02/04/97	JMI	Added BMP_COOKIE for in detecting a .BMP formatted file.
//						Made LoadDib() a private member.  Now Load() will load *.BMP
//						or *.IMG formatted files.
//
//	04/16/97	JMI	Changed comment for operator= overload and parameter name.
//
// 05/21/97 JRD	Fixed a bug in GetPitch.
//
//	Image.h contains the class RImage.  Pal.h contains RPal.  The RImage is used
// to store generic images either with or without palettes.  RPal can also be 
// used alone to store palettes.
//
// The image format sets a standard image format as a middle ground.
// If you wish to create a different image format, such as compressed
// images, then you would supply a convert function that would be able
// to convert from this standard RImage format to your compressed 
// format and a conversion function to convert from your compressed
// format to this standard format.  You can choose to change the pData
// pointer to point to the data in your new format, or you could
// choose to keep the standard form in pData and allocate memory for 
// your compressed version and use m_pSpecial to keep track of it.
//
// If you create a new image format, you should register your
// enumerated image type in image.h in the eImageTypes enum and add 
// your Convert() function pointer to the array of convert functions
// in imageafp.h.  The array of convert function pointers is indexed
// by the image type.
// Then you may add your conversion function either in your own
// file or you could add its prototype to imagecon.h and the
// code to imagecon.cpp.
//
//////////////////////////////////////////////////////////////////////


// Blue include files
#include "Blue.h"

// If PATHS_IN_INCLUDES macro is defined, we can utilized relative
// paths to a header file.  In this case we generally go off of our
// RSPiX root directory.  System.h MUST be included before this macro
// is evaluated.  System.h is the header that, based on the current
// platform (or more so in this case on the compiler), defines 
// PATHS_IN_INCLUDES.  Blue.h includes system.h so you can include that
// instead.
#ifdef PATHS_IN_INCLUDES
	// Green include files
	#include "GREEN/Image/pal.h"

	// Orange include files
	#include "ORANGE/File/file.h"
#else
	// Green include files
	#include "pal.h"

	// Orange include files
	#include "file.h"
#endif // PATHS_IN_INCLUDES


///////////////////////////////////////////////////////////////////////////////
// Macros.
///////////////////////////////////////////////////////////////////////////////

#define WIDTHuint8_t(i)   (((i)+3) & ~3)      // uint32_t aligned
#define WIDTH128(i)		 (((i)+15) & ~15)	 // 128-bit aligned

#define IMAGE_COOKIE	0x20204d49 // Looks like "IM  " in the file
#define IMAGE_CURRENT_VERSION	5 // Current file version.  Change
										  // this number if you change the .IMG
										  // file format.  It will be compared to
										  // the version number in the file as a check

#define BMP_COOKIE	0x4d42		// Looks like "BM" in the file.

///////////////////////////////////////////////////////////////////////////////
// Typedefs.
///////////////////////////////////////////////////////////////////////////////

// Windows Independent DIB BITMAPFILEHEADER representation.
typedef struct
{
	uint16_t	usType;
	uint32_t		ulSize;
	uint16_t	usReserved1;
	uint16_t	usReserved2;
	uint32_t		ulOffBits;
} DIBFILEHEADER;

// Windows Independent DIB BITMAPINFOHEADER representation.
typedef struct
{
	uint32_t			ulSize;
	int32_t			lWidth;
	int32_t			lHeight;
	uint16_t		usPlanes;
	uint16_t		usBitCount;
	uint32_t			ulCompression;
	uint32_t			ulSizeImage;
	int32_t			lXPelsPerMeter;
	int32_t			lYPelsPerMeter;
	uint32_t			ulClrUsed;
	uint32_t			ulClrImportant;
} DIBHEADER, *PDIBHEADER;

//////////////////////////////////////////////////////////////////////
//
//	RImage class 
//
// RImage is a simple wrapper around various types of images.
// This class does not understand any particular image types.
// I'm not sure that the above sentence is true anymore....?
//
//////////////////////////////////////////////////////////////////////
class RImage
{
	public:	// Typedefs and Enums.

		// Insert your type before the END_OF_TYPES enumeration and make
		// an entry for your convert function in the array of conversion 
		// functions afpConvert[] which is in imageafp.h.  The END_OF_TYPES
		// is used as a check against invalid conversion types and must 
		// be the last type in the enum.
		// IMPORTANT NOTE:  The position of the standard types (BMP8 -
		// SCREEN32_ARGB) must remain the same.  Always add your enum before
		// END_OF_TYPES to be safe!  Also remember to add the name of your
		// type to the string ms_astrTypeNames in image.cpp.
		typedef enum eImageTypes
		{
			NOT_SUPPORTED,			// To indicate error on load, etc.
			BMP8,						// Windows BMP 8-bit buffer, RGBQUAD
			SYSTEM8,					// 8-bit buffer with palette in SYSTEM format (Win/Mac/etc)
			SCREEN8_555,			// 8-bit buffer, screen formatted palette 555
			SCREEN8_565,			// 8-bit buffer, screen formatted palette 565
			SCREEN8_888,			// 8-bit buffer, screen formatted palette 888
			BMP24,					// Windows BMP 24-bit buffer, 
			SCREEN16_555,			// 16-bit buffer with pixel values in screen format 555
			SCREEN16_565,			// 16-bit buffer with pixel values in screen format 565
			SCREEN24_RGB,			// 24-bit buffer with pixel values in screen format 888
			SCREEN32_ARGB,			// 32-bit buffer with pixel values in screen Alpha + RGB format (8888)
			FSPR1,					// Used with BLiT Fast Text
			FSPR8,					// Used with BLiT Fast Sprites
			FSPR16,					// Used with BLiT Fast Sprites
			FSPR32,					// Used with BLiT Fast Sprites
			ROTBUF,					// Used with two current live roration/scale algorithms
			SPECIAL,					// IMAGE needs a sophisticated convert call
			FLX8_888,				// 8-bit buffer indexing a 256 color 
										// R, G, B (in that order) palette.  JMI	03/06/96
			IMAGE_STUB,				// Use to make anything APPEAR to be an image
										// special field = per stub info, buffers = NULL
			BMP8RLE,					// 8-bit compressed (Windows RLE8 bitmap) format.
										// Uses PDIB for palette.  JMI	07/22/96
			BMP1,						// Monochrome bitmap.  No palette 
										// (1 == Black, 0 == White).  JMI	09/04/96
			END_OF_TYPES
		} Type;


	public:	// Member vars.
		Type	m_type;						// Image type
		Type	m_typeDestination;			// Type to convert to upon load
											// (New version 2)
		uint32_t		m_ulSize;			// Image data's size
		int16_t			m_sWinWidth;		// Width of image
		int16_t			m_sWinHeight;		// Height of image
		int16_t			m_sWidth;			// Width of buffer   (new version 2)
		int16_t			m_sHeight;			// Height of buffer (new version 2)
		int16_t			m_sWinX;			// Position of image in the buffer
		int16_t			m_sWinY;			// Position of image in the buffer

		int32_t			m_lPitch;			// Pitch of image
		int16_t			m_sDepth;			// Color depth of image
		
		//todo gpu
		uint8_t*		m_pData;			// Pointer to data								
		
		RPal*			m_pPalette;			// Pointer to palette class
		uint8_t*		m_pSpecial;			// Generic pointer for expandability
											// (other image formats)
		uint8_t*		m_pSpecialMem;		// Pointer to allocated special memory
		
		uint8_t*		m_pMem;				// Pointer to the memory buffer
											// (for alloc/dealloc of aligned data)
											// User access in lieu of an AttachData function
		
		// This array of type names should correspond to the above list of
		// enumerated types.  Whenever you add an image type and an enum, 
		// you need to also insert that name into the corresponding place
		//	in this array in image.cpp.  
		// Note that this uses END_OF_TYPES enum item to size the array.
		static char* ms_astrTypeNames[END_OF_TYPES];

	private:
		RPal*			m_pPalMem;		// Pointer to Image allocated palette

	public:

		bool hasalpha = false;

		void MovedToVram();

		// Class initialization
		static void Init(void);

		// Safe method for destroying memory that was originally
		// allocated by Image::CreateData and then detached from
		// the RImage by Image::DetachData.  This routine will use
		// the correct free() function for the memory handle.
		static int16_t DestroyDetachedData(void** hMem);

		// General Constructor
		RImage();

		// Constructor that allocates data for the buffer
		// Same as calling CreateData(ulSize)
		RImage(uint32_t ulSize);

		// Constructor that allocates a buffer and loads a bitmap
		// Same as calling LoadDib(pszFilename, ulType)
		RImage(char* pszFilename);

		// General Destructor
		~RImage();

		// Equals overload.
		// Note that this function could fail.
		RImage& operator=(const RImage& imSrc);

		// Create IMAGE's data using the specified values.
		int16_t CreateData(	// Returns 0 if successful
			uint32_t ulSize);	// Size of data

		// Create IMAGE's data utilizing passed in fields.
		// Calls CreateData(uint32_t) to do the allocation.
		int16_t CreateImage(			// Returns 0 if successful.
			int16_t	sWidth,				// Width of new buffer.
			int16_t	sHeight,				// Height of new buffer.
			Type type,			// Type of new buffer.
			int32_t	lPitch	= 0L,		// Pitch of new buffer or 0 to calculate.
			int16_t	sDepth	= 8);		// Color depth of new buffer.

		// Detach the data from the Image.  This function returns a pointer
		// to the memory buffer which can and should be freed by whoever
		// detached it.  Alternatively you can supply pointers to void* 
		// that will be given the memory and data pointers for the Image 
		// buffer.  This function is usefull when doing conversions between
		// image types.  You can detach the buffer from the Image, have the
		// Image create a new buffer (for the converted data) and then free
		// the detached buffer when you're done with the conversion.
		int16_t DetachData(void** pMem, void** pData);
		void* DetachData();

		// Destroy IMAGE's data
		int16_t DestroyData();

		// Allow the user to set the data pointer.
		int16_t SetData(void* pData);

		// Set the pPalette pointer to a given RPal
		int16_t SetPalette(RPal* pPal);

		// Create palette and assign its pointer to pPalette
		int16_t CreatePalette(uint32_t ulSize);

		// Create a palette but do not create a data buffer for the palette
		int16_t CreatePalette(void);

		// Detach the palette from the Image and return a pointer to it.
		// whoever detaches the palette is responsible for it afterward
		// and they must free it when they are done.
		RPal* DetachPalette();

		// Destroy the image's palette
		int16_t DestroyPalette();
	
		// Load the standard image formats, ie. those that do not
		// include m_pSpecial data
		int16_t Load(char* pszFilename);

		// This version takes an open RFile pointer and reads the
		// standard image from the file.  This may be useful if you
		// have a special image type that uses the m_pSpecial pointer.  You
		// can write your own load function that opens a RFile
		int16_t Load(RFile* pcf);

		// Converts the RImage from its current type to the new type
		// by converting from the current form to the standard and then
		// converting the standard into the new type.
		Type Convert(Type typeNew);

		// Query functions
		int16_t GetHeight(void) 	{return m_sHeight;};
		int16_t GetWidth(void)		{return m_sWidth;};
		static int32_t GetPitch(int16_t sWidth, int16_t sDepth)
			{return ((int32_t)sWidth * ((int32_t)sDepth / 8L) + 0x0000000F) & 0xFFFFFFF0;}
		Type GetType(void)		{return m_type;};

		//todo gpu
		// Memory access functions
		//pvr_ptr_t GetBuffer(void)	{return m_pData;};
		
		uint8_t* GetBuffer(void) { return m_pData; };
		uint8_t* GetMemory(void)	{return m_pMem;};

	private:
		// Loads a DIB into a standard RImage format.
		int16_t	LoadDib(char* pszFilename);

		// Loads a DIB from an open RFile
		int16_t LoadDib(RFile* pcf);

		// Writes the data in one chunk if the buffer is the same
		// size as the image, or line by line if the buffer is larger
		// than the image.  If the buffer is smaller than the image, 
		// then you have some problem.
		int16_t WritePixelData(RFile* pcf) const;

		// Reads the data in one chunk if the buffer is the same
		// size as the image, or line by line if the buffer is larger
		// than the image.  If the buffer is smaller than the image 
		// then the image won't fit and the program will probably 
		// crash and it will be your fault.
		int16_t ReadPixelData(RFile* pcf);

		// Initialize all members.  Calling this when m_pMem* is set is not a good idea.
		void InitMembers(void);

		//	To allocate memory for the data buffers of CPal
		static int16_t sCreateMem(void **hMem,U64 ulSize);

		//	To allocate memory and return a pointer aligned to 128-bits
		//	for optimum blit speed.  This is the function used by
		//	CImage when it creates memory for the image buffers.
		static int16_t sCreateAlignedMem(void **hMem, void **hData, U64 ulSize);

		//	To free the data buffers of CPal and CImage that were created 
		//	using either sCreateMem() or sCreateAlignedMem()
		static int16_t sDestroyMem(void **hMem);


	public:
		// Who's our friend?  RPal!  Yayayyayay.
		// Perhaps, since these two genderlessnesses are so close, they
		// should be friends /wink /wink.
		friend class RPal;
		// RImageFile is our friend so it can load formats for us.
		friend class RImageFile;
};

//////////////////////////////////////////////////////////////////////
//
//	RImageInit class
//
// This class is used to create several arrays of function pointers
// for special image types.  A special image type may support, 
// special allocation and deallocation, conversion functions, 
// and load and save functions.  This class replaces the DYNALINK 
// module.  DYNALINK was used in the previous version to provide
// support for ConvertTo and ConvertFrom functions for special image
// types so that the convert functions could be in different files, 
// and so that convert functions that were needed for a particular
// application were automatically included by including the blit
// module that was being used.
//
//////////////////////////////////////////////////////////////////////

// Conversion from extended to standard function typedef
typedef short (*CONVFROMFUNC)(RImage* pImage);
// Conversion to extended from standard function typedef
typedef short (*CONVTOFUNC)(RImage* pImage);
// Load extension for special types - loads m_pSpecial data
typedef short (*LOADFUNC)(RImage* pImage, RFile* pcf/*, uint32_t ulVersion*/);
// Save extension for special types - saves m_pSpecial data
typedef short (*SAVEFUNC)(RImage* pImage, RFile* pcf/*, uint32_t ulVersion*/);
// Special data allocation function
typedef short (*ALLOCFUNC)(RImage* pImage);
// Special data deallocation function
typedef short (*DELETEFUNC)(RImage* pImage);


class RImageSpecialFunc : public RImage
{
	public:

		RImageSpecialFunc(Type type,
								CONVTOFUNC pfnConvertTo,
								CONVFROMFUNC pfnConvertFrom,
								LOADFUNC pfnLoad,
								SAVEFUNC pfnSave,
								ALLOCFUNC pfnAlloc,
								DELETEFUNC pfnDelete)
			{
				ASSERT(type < END_OF_TYPES);
				ASSERT(ms_apfnConvTo[type] == NULL);
				ms_apfnConvTo[type] = pfnConvertTo;

				ASSERT(ms_apfnConvFrom[type] == NULL);
				ms_apfnConvFrom[type] = pfnConvertFrom;

				ASSERT(ms_apfnLoad[type] == NULL);
				ms_apfnLoad[type] = pfnLoad;

				ASSERT(ms_apfnSave[type] == NULL);
				ms_apfnSave[type] = pfnSave;

				ASSERT(ms_apfnAlloc[type] == NULL);
				ms_apfnAlloc[type] = pfnAlloc;

				ASSERT(ms_apfnDelete[type] == NULL);
				ms_apfnDelete[type] = pfnDelete;
			};

	friend class RImage;
	// RImageFile is our friend so it can load formats for RImage.
	friend class RImageFile;

	protected:
		static CONVTOFUNC		ms_apfnConvTo[END_OF_TYPES];
		static CONVFROMFUNC	ms_apfnConvFrom[END_OF_TYPES];
		static LOADFUNC		ms_apfnLoad[END_OF_TYPES];
		static SAVEFUNC		ms_apfnSave[END_OF_TYPES];
		static ALLOCFUNC		ms_apfnAlloc[END_OF_TYPES];
		static DELETEFUNC		ms_apfnDelete[END_OF_TYPES];
};


// These macros are used to access each type of special function

#define GETTOFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnConvTo[lIndex]

#define GETFROMFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnConvFrom[lIndex]

#define GETLOADFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnLoad[lIndex]

#define GETSAVEFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnSave[lIndex]

#define GETALLOCFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnAlloc[lIndex]

#define GETDELETEFUNC(lIndex) \
	RImageSpecialFunc::ms_apfnDelete[lIndex]


// This macro needs to be called at file scope of RImage.cpp so that
// the arrays of special function pointers are allocated and initialized
// to NULL.  It will instantiate the RImageSpecialFunc class and its
// arrays of function pointers.  
//
// The arrays are set to the size END_OF_TYPES since the special
// function pointers will be indexed by the image type.

#define IMAGELINKINSTANTIATE() \
	CONVTOFUNC RImageSpecialFunc::ms_apfnConvTo[END_OF_TYPES] = { NULL, }; \
	CONVFROMFUNC RImageSpecialFunc::ms_apfnConvFrom[END_OF_TYPES] = { NULL, }; \
	LOADFUNC RImageSpecialFunc::ms_apfnLoad[END_OF_TYPES] = { NULL, }; \
	SAVEFUNC RImageSpecialFunc::ms_apfnSave[END_OF_TYPES] = { NULL, }; \
	ALLOCFUNC RImageSpecialFunc::ms_apfnAlloc[END_OF_TYPES] = { NULL, }; \
	DELETEFUNC RImageSpecialFunc::ms_apfnDelete[END_OF_TYPES] = { NULL, }

// This macro is used to add the special functions to the image's 
// list.  You must specify a function pointer for each of the 6 special
// types or NULL if your special type does not require or support one
// or more types.  For example, if you support convert to/from and 
//	save/load but do not require any additional buffers or data structures
// then you must provide the functions for convert to/from and load/save 
// and then specify NULL, NULL for the alloc and delete functions.
//
// ulImageType = one of the enumerated image types registered in image.h
// pTo = function pointer to your ConvertTo function
// pFrom = function pointer to your ConvertFrom function
// pLoad = function pointer to your Load function that reads just your
//			  special data.  The standard RImage information is loaded by 
//			  the RImage::Load function and this function will be called
//			  when it gets to the m_pSpecial data for your special image type
// pSave = function pointer to your Save function that writes just your
//			  special data.  The standard RImage information is saved by
//			  the CImgae::Save function and this function will be called
//			  when it is time to write the m_pSpecial data. 
// pAlloc = function pointer to your special memory allocation function.
//			   If your m_pSpecial data is a class or contains multiple
//			   pointers to other data buffers, then you should provide a
//				function that can allocate this data based on the standard
//			   information in the RImage
// pDelete = function pointer to your special memory deallocation 
//				 function.  If your m_pSpecial data is a class or contains
//				 multiple pointers to other data buffers that need to be
//				 freed when the RImage destructor is called, then you
//				 should provide a function that will clean up your m_pSpecial
//				 data.

#define IMAGELINKLATE(type, pTo, pFrom, pLoad, pSave, pAlloc, pDel) \
	static RImageSpecialFunc imSpecial##type(RImage::type, pTo, pFrom, pLoad, pSave, pAlloc, pDel)


///////////////////////////////////////////////////////////////////////////////
// The problem:
// Converters, Loaders, Savers, Allocators, and Deleters for non-standard types
// are lunk in at run time.  The linker is generally not smart enough (or dumb
// enough) to leave this code in the resulting executable unless the functions
// are explicitly referenced by something else that is to be included in the
// executable.
// 
// TOUCH macros:
// These macros allow you to 'touch' a convert function to make sure it will
// be included in the final exe.  It is not recommended that they be used in
// library code b/c of two problems:
// 1) They cannot be used twice.  That is, no two modules can contain two
// references to any *TOUCH(type) for the same type.
//	2) They will only work if the module that contains the *TOUCH(type) is
// included in the exe.  A module that would otherwise be dropped from the exe
// by the linker with a *TOUCH(type) will do no one any good.
//
// So use these in your application level modules to cause the particular
// type's equivalent ConvertTo, ConvertFrom, Save, Load, Alloc, and/or Delete
// func to be included in your exe.
//
//	Non-standard func:						Equivalent TOUCH macro:
//	=====================					========================
//	ConvertToTYPE								CONVTOTOUCH(TYPE)
//	ConvertFromTYPE							CONVFROMTOUCH(TYPE)
//	SaveTYPE										SAVETOUCH(TYPE)
//	LoadTYPE										LOADTOUCH(TYPE)
//	AllocTYPE									ALLOCTOUCH(TYPE)
//	DeleteTYPE									DELETETOUCH(TYPE)
//
// THIS METHOD HAS NOT BEEN TESTED WITH THE MAC COMPILER.  I presume the logic
// for dropping stuff is the same.  There is another plausible solution for
// this problem under Metrowerks.  Let me know (Jo8n) if this doesn't work for
// you!  Let me know if it does (that way I can remove this message).
//
///////////////////////////////////////////////////////////////////////////////
#define CONVTOTOUCH(TYPE)		extern void ReferenceConvTo##TYPE(void)		\
											{														\
											extern short ConvertTo##TYPE(RImage*);		\
											ConvertTo##TYPE(NULL);							\
											}

#define CONVFROMTOUCH(TYPE)	extern void ReferenceConvFrom##TYPE(void)		\
											{														\
											extern short ConvertFrom##TYPE(RImage*);	\
											ConvertFrom##TYPE(NULL);						\
											}

#define SAVETOUCH(TYPE)			extern void ReferenceSave##TYPE(void)			\
											{														\
											extern short Save##TYPE(RImage*, RFile*); \
											Save##TYPE(NULL, NULL); 						\
											}

#define LOADTOUCH(TYPE)			extern void ReferenceLoad##TYPE(void)			\
											{ 														\
											extern short Load##TYPE(RImage*, RFile*); \
											Load##TYPE(NULL, NULL); 						\
											}

#define ALLOCTOUCH(TYPE)		extern void ReferenceAlloc##TYPE(void)			\
											{ 														\
											extern short Alloc##TYPE(RImage*); 			\
											Alloc##TYPE(NULL); 								\
											}

#define DELETETOUCH(TYPE)		extern void ReferenceDelete##TYPE(void)		\
											{ 														\
											extern short Delete##TYPE(RImage*); 		\
											Delete##TYPE(NULL);								\
											}

#endif //IMAGE_H

//////////////////////////////////////////////////////////////////////
// EOF
//////////////////////////////////////////////////////////////////////
