////////////////////////////////////////////////////////////////////////////////
//
// 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
//
//////////////////////////////////////////////////////////////////////
//
//	IMAGECON.CPP
//   
//	Created on 		09/28/95	BRH 
// Implemented on 09/28/95 BRH
//
// 09/28/95	BRH	Standard conversion functions for the standard
//						image types.  The two main standards are 8 and 24
//						bit images.  The standard converters are explained
//						below
//
//	11/03/95 BRH	Added support for RPal's new sPalEntrySize.  Any
//						conversion that changes the palette will also 
//						update this variable.  
//
//	11/06/95 BRH	Fixed the ConvertToSCREEN8_888 to use the proper
//						24-bit palette entries rather than the 32-bit
//						that it was using.
//
//	11/07/95	JMI	Changed all occurrences of RGBQUAD to IM_RGBQUAD &
//						RGBTRIPLE to IM_RGBTRIPLE.
//
// 11/08/95 BRH	Added several direct conversions to BMP8 and BMP24.
//						Previously we had BMP8 and BMP24 as our two base
//						types which then were converted to SCREEN8_xxx formats
//						and others.  By providing a few more direct conversions
//						I can then provide almost any other conversion by
//						calling two conversion functions, one from the current
//						to BMP8 and then from BMP8 to the new format.  The 
//						only conversions not supported are high color or
//						true color images being converted to palette images.
//
// 11/15/95	BRH	Change the conversion routines that deal with palettes
//						so that the images keep the original RPal object in
//						their pPalette pointers when the are converted.  
//						Previously the conversion routines detached the
//						palette from the RImage and then created a new palette
//						and attached that to the RImage.  This causes trouble
//						if there are other external pointers to the same RPal, 
//						for example if several images use the same palette we
//						don't want to throw the palette out.  Now the image
//						keeps the same RPal object and only the palette's data
//						is discarded during the conversion.
//
//	11/20/95 BRH	Finished up all of the cross conversions between formats
//						using intermediate BMP8 or BMP24 translations when necessary.
//						Currently any standard format can be converted to any other
//						standard format with the exception that 32, 24, or 16 bit 
//						images cannot be converted to any of the 8 bit formats due
//						to the lack of a good color reduction algorithm.  
//
// 01/15/96 JMI	Changed the array of conversion functions to a dynamic
//						linking mechanism of ConvertTo and ConvertFrom function
//						pointers so that new conversion functions can be added in
//						.cpp files other than imagecon.cpp.  
//
//	01/16/96	BRH	Added calls to RImage::GetPitch(width,depth) to calculate
//						the 128-bit aligned pitch for converted image types.  
//						previously, several of the conversion functions forgot
//						to change the pitch for the new format.
//
// 01/19/96 BRH	Fixed a bug in creating new buffers.  Most calls were
//						incorrectly using width*height*(depth/8) where they should
//						have been using pitch instead of width.
//
// 02/27/95	BRH	Changed over from using DYNALINK to the RImageSpecialFunc
//						class for Conversion functions.  The new class is based on
//						the same concept as DYNALINK but is specialized for RImage
//						in that it supports 6 special function types for conversion
//						to/from, load/save, and alloc/delete.  I moved the instantiation
//						of the static arrays from imagecon.cpp to image.cpp since
//						it now instantiates 6 arrays, 4 of which are not conversion
//						related.  Then I changed the calls to LINKLATE macros (DYNALINK)
//						to IMAGELINKLATE macros (RImageSpecialFunc).
//
//	07/22/96	JMI	Added ConvertFromBMP8RLE to allow LoadDib to load RLE8
//						compressed DIBs.  BMP8RLE format can be used as any other
//						image format.  Will implement ConvertToBMP8RLE soon.
//
//	07/23/96	JMI	Added ConvertToBMP8RLE to allow one to convert into
//						BMP8RLE (RLE8 Windows' bitmap compressed format).  The convert
//						flips upside down as it compresses making it official
//						as far as BMP files go.  SaveDib is aware of this use of 
//						RLE8 and can save these preserving compression.
//						Also, made ConvertFromBMP8RLE flip the image so you get
//						a DIB that is upside down as far as DIBs go, but right side
//						up to the naked eye.  This is functionality was implemented
//						since LoadDib does this as well.
//
//	08/04/96 MJR	Commented-out the "pImage" parameter to ConvertNoSupport()
//						to avoid compiler warning about "unused variable".
//						Also modified ConvertToSystem() to use WIN32 instead of
//						_WINDOWS and to use MAC instead of _MAC.  However, note that
//						ConvertToSystem() still does nothing on the mac.
//
//	09/04/96	JMI	Added BMP1 IMAGELINKLATE's and corresponding ConvertToBMP1()
//						and ConvertFromBMP1().  BMP8 is, as usual, the only type 
//						convertible to BMP1.
//
//	10/10/96	JMI	ConvertToBMP24() was not checking for error return from
//						CreateData() and so it was crashing when memory was
//						low.
//
//	10/30/96	JMI	Changed:
//						Old label:		New label:
//						=========		=========
//						RImage			RImage
//						RPal				RPal
//						uint32_t ulType	RImage::Type ulType
//						
//						Removed #include of "imagetyp.h" b/c it has been obsoleted.
//						Removed #include of "imagecon.h" b/c all it does is include
//						image.h and then redeclare RImage (now RImage anyway) and
//						replaced with #include of image.h.
//
//	11/01/96	JMI	Changed all members of image to be preceded by m_ (e.g.,
//						sDepth to 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).  Changed ulType to
//						m_type and ulDestinationType to m_typeDestination.
//
//	11/06/96 MJR	Added "RImage::: before many instances of BMP8, BMP24, etc.
//						This was suddenly required because the IMAGELINKLATE macro
//						no longer used the "using" syntax which had, as a side-effect,
//						allowed the use of the enums without a preceeding "RImage::".				
//
//	11/08/96	JMI	Added more "RImage::"s where necessary in the #ifdef WIN32
//						block.
//
//	11/08/96	JMI	Changed reference of BMP8RLE to RImage::BMP8RLE in an ASSERT.
//
// Standard Converters:
//
// Buffer Conversions:
//
// BMP8 (8-bit buffer 32-bit color pal)	-> 16-bit buffer (555)
// BMP8 (8-bit buffer 32-bit color pal)	-> 16-bit buffer (565)
// BMP8 (8-bit buffer 32-bit color pal)	-> 24-bit buffer (888)	RGB
// BMP8 (8-bit buffer 32-bit color pal)	-> 32-bit buffer (8888) ARGB
// BMP24 (24-bit buffer)						-> 16-bit buffer (555)
// BMP24 (24-bit buffer)						-> 16-bit buffer (565)
// BMP24 (24-bit buffer)						-> 32-bit buffer (8888) ARGB
//
// Palette Conversions:
//
// BMP8 (IM_RGBQUAD)	-> 555 Palette
// BMP8 (IM_RGBQUAD) -> 565 Palette
// BMP8 (IM_RGBQUAD) -> 888 Palette
// BMP8 (IM_RGBQUAD) -> SYSTEM Palette (for setting colors on a platform
//							basis) Windows = IM_RGBQUAD, Mac = Mac System Pal
//							
//
//////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <string.h>

#include "Image.h"

//////////////////////////////////////////////////////////////////////
// Prototypes.
//////////////////////////////////////////////////////////////////////
int16_t	ConvertNoSupport(RImage* pImage);
int16_t	ConvertToBMP8(RImage* pImage);
int16_t	ConvertToBMP24(RImage* pImage);

IMAGELINKLATE(BMP8, ConvertToBMP8, NULL, NULL, NULL, NULL, NULL);

//////////////////////////////////////////////////////////////////////
// More non-standard, always supported types:
//////////////////////////////////////////////////////////////////////

// BMP compression format (BMP8RLE).
int16_t ConvertToBMP8RLE(RImage* pImage);
int16_t ConvertFromBMP8RLE(RImage* pImage);
// Link in conversion functions.
IMAGELINKLATE(BMP8RLE, ConvertToBMP8RLE, ConvertFromBMP8RLE, NULL, NULL, NULL, NULL);

// Monochrome BMP (BMP1).
int16_t ConvertToBMP1(RImage* pImage);
int16_t ConvertFromBMP1(RImage* pImage);
// Link in conversion functions.
IMAGELINKLATE(BMP1, ConvertToBMP1, ConvertFromBMP1, NULL, NULL, NULL, NULL);

//////////////////////////////////////////////////////////////////////
//
// ConvertNoSupport:
//
//	Catch function in case somebody passes in a format that is not
// supported.  This function will just return RImage::NOT_SUPPORTED
//
//////////////////////////////////////////////////////////////////////

int16_t ConvertNoSupport(RImage* /*pImage*/)
{
	TRACE("RImage::Convert - Conversion not supported - Invalid image type\n");
	return RImage::NOT_SUPPORTED;
}

//////////////////////////////////////////////////////////////////////
//
// ConvertToBMP8
//
// For now this conversion is not supported.  RImage::BMP8 is a standard
// load format so it is not apparent at this time why one couldn't
// simply use the load function to obtain a RImage::BMP8 format.  We don't 
// see the need to convert from one of the other formats into RImage::BMP8 
// but if it becomes necessary or convenient then it can be supported
//
//////////////////////////////////////////////////////////////////////

int16_t	ConvertToBMP8(RImage* pImage)
{
	int16_t sReturn;

	switch (pImage->m_type)
	{
		case RImage::BMP8:
		{
			sReturn = RImage::BMP8;
			break;
		}

		case RImage::SYSTEM8:
		{
			#ifdef _WINDOWS
				pImage->m_type = RImage::BMP8;
				pImage->m_pPalette->m_type = RPal::PDIB;
				return RImage::BMP8;
			#endif
			break;
		}

		case RImage::SCREEN8_555:
		{
			// Make a copy of the original palette
			RPal* p555Pal = new RPal();
			*p555Pal = *pImage->m_pPalette;

			// Detach the original palette data from the Image's palette
			p555Pal->m_pData = pImage->m_pPalette->DetachData();

			// Create new palette data for the pImage
			pImage->m_pPalette->CreateData((p555Pal->m_sStartIndex + p555Pal->m_sNumEntries) * RPal::GetPalEntrySize(RPal::PDIB));
			pImage->m_pPalette->m_type = RPal::PDIB;
			pImage->m_pPalette->m_sPalEntrySize = RPal::GetPalEntrySize(RPal::PDIB);

			uint16_t* usp555 = (uint16_t*) p555Pal->m_pData;
			uint32_t* ulpDib = (uint32_t*) pImage->m_pPalette->m_pData;

			int16_t i;
		
			// The 555 viewed as uint16_t as xR5|G5|B5
			//         viewed as 2 BYTES   G3|B5|x|R5|G2
			// The DIB viewed as uint32_t is Reserved|R|G|B
			//         viewed as 4 BYTES  B|G|R|Reserved

			for (i = p555Pal->m_sStartIndex; i < p555Pal->m_sStartIndex + p555Pal->m_sNumEntries; i++)
				ulpDib[i] = (uint32_t) (((usp555[i] & 0x7c00) << 9) + // Red
				                     ((usp555[i] & 0x03e0) << 6) + // Green
											((usp555[i] & 0x001f) << 3)); // Blue

			delete p555Pal;

			pImage->m_type = RImage::BMP8;
			sReturn = RImage::BMP8;
			break;
		}

		case RImage::SCREEN8_565:
		{
			// Make a copy of the original palette
			RPal* p565Pal = new RPal();
			*p565Pal = *pImage->m_pPalette;

			// Detach the original palette data from the Image's palette
			p565Pal->m_pData = pImage->m_pPalette->DetachData();

			// Create new palette data for the pImage
			pImage->m_pPalette->CreateData((p565Pal->m_sStartIndex + p565Pal->m_sNumEntries) * RPal::GetPalEntrySize(RPal::PDIB));
			pImage->m_pPalette->m_type = RPal::PDIB;
			pImage->m_pPalette->m_sPalEntrySize = RPal::GetPalEntrySize(RPal::PDIB);

			uint16_t* usp565 = (uint16_t*) p565Pal->m_pData;
			uint32_t* ulpDib = (uint32_t*) pImage->m_pPalette->m_pData;

			int16_t i;
		
			// The 565 when viewed as uint16_t  R5|G6|B5
			//              viewed as 2 BYTES G3|B5|R5|G3
			// The DIB when viewed as uint32_t   Reserved|R|G|B
			//              viewed as 4 BYTES B|G|R|Reserved

			for (i = p565Pal->m_sStartIndex; i < p565Pal->m_sStartIndex + p565Pal->m_sNumEntries; i++)
				ulpDib[i] = (uint32_t) (((usp565[i] & 0xf800) << 8) + // Red
				                     ((usp565[i] & 0x07e0) << 5) + // Green
											((usp565[i] & 0x001f) << 3)); // Blue

			delete p565Pal;

			pImage->m_type = RImage::BMP8;
			sReturn = RImage::BMP8;
			break;
		}

		case RImage::SCREEN8_888:
		{
			// Make a copy of the original palette
			RPal* p888Pal = new RPal();
			*p888Pal = *pImage->m_pPalette;

			// Detach the original palette data form the Image's palette
			p888Pal->m_pData = pImage->m_pPalette->DetachData();

			// Create new palette data for the pImage
			pImage->m_pPalette->CreateData((p888Pal->m_sStartIndex + p888Pal->m_sNumEntries) * sizeof(IM_RGBQUAD));
			pImage->m_pPalette->m_type = RPal::PDIB;
			pImage->m_pPalette->m_sPalEntrySize = RPal::GetPalEntrySize(RPal::PDIB);

			IM_RGBTRIPLE* tp888 = (IM_RGBTRIPLE*) p888Pal->m_pData;
			IM_RGBQUAD* qpDib = (IM_RGBQUAD*) pImage->m_pPalette->m_pData;
		
			int16_t i;

			// The DIB format when viewed as a IM_RGBQUAD = B|G|R|Reserved
			// The 888 palette     viewed as IM_RGBTRIPLE   B|G|R

			for (i = p888Pal->m_sStartIndex; i < p888Pal->m_sStartIndex + p888Pal->m_sNumEntries; i++)
			{
			 	qpDib[i].rgbBlue = tp888[i].rgbtBlue;
				qpDib[i].rgbGreen = tp888[i].rgbtGreen;
				qpDib[i].rgbRed = tp888[i].rgbtRed;
				qpDib[i].rgbReserved = 0;
			}

			delete p888Pal;

			pImage->m_type = RImage::BMP8;
			sReturn = RImage::BMP8;
			break;
		}
	
		default:
		{
			sReturn = RImage::NOT_SUPPORTED;
			break;
		}
	}

	return sReturn;
}

//////////////////////////////////////////////////////////////////////
//
// Converts from the Window's compression format for 8 bit BMPs (RLE8)
// RImage::BMP8RLE to RImage::BMP8 format.  Palette is not touched.
// 
// Description of this process from Win32 documentation:
// This format can be compressed in encoded or absolute modes. Both 
// modes can occur anywhere in the same bitmap. 
// �	Encoded mode consists of two bytes: the first byte specifies the
// number of consecutive pixels to be drawn using the color index 
// contained in the second byte. In addition, the first byte of the pair 
// can be set to zero to indicate an escape that denotes an end of line, 
// end of bitmap, or delta. The interpretation of the escape depends on 
// the value of the second byte of the pair, which can be one of the 
// following: 
//   
// Value	Meaning
// 
// 0	End of line.
// 1	End of bitmap.
// 2	Delta. The two bytes following the escape contain unsigned values 
// indicating the horizontal and vertical offsets of the next pixel from 
// the current position.
//
// �	In absolute mode, the first byte is zero and the second byte is a 
// value in the range 03H through FFH. The second byte represents the 
// number of bytes that follow, each of which contains the color index 
// of a single pixel. When the second byte is 2 or less, the escape has 
// the same meaning as in encoded mode. In absolute mode, each run must 
// be aligned on a word boundary. 
//   
//
//////////////////////////////////////////////////////////////////////
int16_t ConvertFromBMP8RLE(RImage* pImage)
	{	
	return 0;
	}

//////////////////////////////////////////////////////////////////////
//
// Converts to the Window's compression format for 8 bit BMPs (RLE8)
// RImage::BMP8RLE from RImage::BMP8.  Palette is not touched.  See
// description of this compression in comment header for 
// ConvertFromBMP8RLE.
//
//////////////////////////////////////////////////////////////////////
int16_t ConvertToBMP8RLE(RImage* pImage)
	{
	return 0;
	}

//////////////////////////////////////////////////////////////////////
//
// Converts from RImage::BMP1 to RImage::BMP8.  Palette is not touched, but
// is NOT significant to BMP1 format (1 == Black, 0 == White).
//
//////////////////////////////////////////////////////////////////////
int16_t ConvertFromBMP1(RImage* pImage)
	{	
	return 0;
	}

//////////////////////////////////////////////////////////////////////
//
// Converts to RImage::BMP1 from RImage::BMP8.  Palette is not touched, but
// is NOT significant to this format (1 == Black, 0 == White).
//
//////////////////////////////////////////////////////////////////////
int16_t ConvertToBMP1(RImage* pImage)
	{
		return 0;
	}


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