#include	"mergelin.h"

#if LITTLE_ENDIAN

#define	INTEL_SWAP16( value )	value = REVERSEu16( value )
#define	INTEL_SWAP32( value )	value = REVERSEu32( value )

#else

#define	INTEL_SWAP16( value )
#define	INTEL_SWAP32( value )

#endif

//----------------------------------------------------------------------------------------
// Divisor to shift count table
//----------------------------------------------------------------------------------------
 CHAR	cnt_to_shifts[256] =
{
	0,
	1,
	-1,	
	2,
	-1,-1,-1,
	3,
	-1,-1,-1,-1, -1,-1,-1,
	4,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,
	5,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,
	6,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,
	7,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,
	8
};


//----------------------------------------------------------------------------------------
// Merge lines (1 - 8 bits)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_px1_8( LONG line_cnt, LONG dst_cnt, 
													LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
													ULONG *src, ULONG *dst )
{
	ULONG		src_word;
	ULONG		dst_word;
	LONG		shift_bits;
	ULONG		*merge_buf;

	shift_bits = 32 - src_bits;																// # of shifts to the right for the first pixel

	src += src_bit_offset >> 5;																// pointer to first source word
	src_bit_offset &= 31;
	dst_word = 0;																							// only for the compiler (warning)
	dst = (ULONG *) ((UCHAR *) dst + dst_length );						// points behind the buffer
	dst -= dst_cnt + 1;
	merge_buf = dst;

	if ( line_cnt == 0 )
	{	
		while ( dst_cnt >= 0 )
		{
			*merge_buf++ = *src++;
			dst_cnt--;
		}
	}
	else
	{
		LONG		i;
		LONG		j;

		if ( line_cnt > 255 )
			line_cnt = 255;
		
		for ( j = dst_cnt; j >= 0; j-- )
			*merge_buf++ = *src++;

		for ( i = line_cnt - 1; i >= 0; i-- )
		{
			src = (ULONG *) ((UCHAR *) src + src_line_offset );
			merge_buf = (ULONG *) dst;

			for ( j = dst_cnt; j >= 0; j-- )
			{
				src_word = *src++;
				dst_word = *merge_buf;

				for ( src_bit_offset = -32; src_bit_offset < 0; src_bit_offset += src_bits )
				{
					ULONG	src_color;
					ULONG	dst_color;

					src_color = src_word >> shift_bits;
					dst_color = dst_word >> shift_bits;

					src_word <<= src_bits;
					dst_word <<= src_bits;

					if ( src_color > dst_color )
						dst_color = src_color;

					dst_word |= dst_color;
				}
				*merge_buf++ = dst_word;
			}
		}
	}
	return( dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (8 bits, 1 component)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_G8_G8( LONG line_cnt, LONG dst_cnt, 
												  LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
												  UCHAR *src, UCHAR *dst )
{
	LONG		shifts;

	(void) src_bits;

	src += ( src_bit_offset >> 5 ) << 2;											// pointer to the first source word
	dst_cnt++;

	if ( line_cnt == 0 )																			// only one line?
	{	
		ULONG	*merge_buf;
		
		dst += dst_length;
		dst -= dst_cnt << 2;
		merge_buf = (ULONG *) dst;
		
		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *((ULONG *) src );
			src += 4;
			dst_cnt--;
		}
	}
	else																											// multiple lines
	{
		UWORD	*merge_buf;
		LONG		i;
		LONG		j;

		if ( line_cnt > 255 )
			line_cnt = 255;																				// limit that to 256 lines (no details anymore - really .-)

		merge_buf = (UWORD *) dst;
		dst_cnt <<= 2;																					// # of destination pixels

		for ( j = dst_cnt; j > 0; j-- )
			*merge_buf++ = *src++;

		for ( i = line_cnt - 1; i >= 0; i-- )										// add the following lines
		{
			src += src_line_offset;																// next destination line
			merge_buf = (UWORD *) dst;

			for ( j = dst_cnt; j > 0; j-- )
				*merge_buf++ += *src++;
		}

		dst += dst_length;																			// points behind the buffer
		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )																			// 2^n lines?
		{
			while ( dst_cnt > 0 )
			{
				*( --dst ) = (UCHAR) (*( --merge_buf ) >> shifts );
				dst_cnt--;
			}
		}
		else																										// use division
		{
			line_cnt++;																						// number of lines

			while ( dst_cnt > 0 )
			{
				*( --dst ) = (UCHAR) (*( --merge_buf ) / line_cnt );
				dst_cnt--;
			}
		}
	}
	return((ULONG *) dst );																		// pointer to the merged line
}

//----------------------------------------------------------------------------------------
// Merge lines (16 bits, 3 components)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_xRGB15_xRGB15( LONG line_cnt, LONG dst_cnt, 
																	LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
																	UWORD *src, UWORD *dst )
{
	ULONG	src_color;
	ULONG	dst_word;
	LONG	shifts;

	(void) src_bits;

	src += ( src_bit_offset >> 5 ) << 1;
	dst = (UWORD *) ((UCHAR *) dst + dst_length );

	if ( line_cnt == 0 )
	{	
		ULONG	*merge_buf;
		
		dst = (UWORD *) ((ULONG *) dst - ( dst_cnt + 1 ));
		merge_buf = (ULONG *) dst;
		
		while ( dst_cnt >= 0 )
		{
			*merge_buf++ = *((ULONG *) src );
			src += 2;
			dst_cnt--;
		}
	}
	else
	{
		UWORD	*merge_buf;
		LONG		i;
		LONG		j;

		if ( line_cnt > 255 )
			line_cnt = 255;

		dst -= ( dst_cnt + 1 ) << 2;
		merge_buf = (UWORD *) dst;

		dst_cnt += dst_cnt + 1;																	// number of destination pixels - 1

		for ( j = dst_cnt; j >= 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP16( src_color );

			*merge_buf++ = 0;
			*merge_buf++ = ( src_color >> 10 ) & 0x001f;
			*merge_buf++ = ( src_color >> 5 ) & 0x001f;
			*merge_buf++ = src_color & 0x001f;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )
		{
			src = (UWORD *) ((UCHAR *) src + src_line_offset );
			merge_buf = dst;

			for ( j = dst_cnt; j >= 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP16( src_color );

				merge_buf++;
				*merge_buf++ += ( src_color >> 10 ) & 0x001f;
				*merge_buf++ += ( src_color >> 5 ) & 0x001f;
				*merge_buf++ += src_color & 0x001f;
			}
		}

		dst = (UWORD *) merge_buf;

		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )
		{
			while ( dst_cnt >= 0 )
			{
				dst_word =   (ULONG) *( --merge_buf ) >> shifts;					// blue
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 5;		// green
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 10;	// red
				--merge_buf;

				INTEL_SWAP16( dst_word );
				*( --dst ) = (UWORD) dst_word;
				dst_cnt--;
			}
		}
		else
		{
			line_cnt++;

			while ( dst_cnt >= 0 )
			{
				dst_word =   (ULONG) ( *( --merge_buf ) / line_cnt );					// blue
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 5;		// green
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 10;	// red
				--merge_buf;

				INTEL_SWAP16( dst_word );
				*( --dst ) = (UWORD) dst_word;		
				dst_cnt--;
			}
		}
	}
	return((ULONG *) dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (16 bits, 2 independent components)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_AB16_AB16( LONG line_cnt, LONG dst_cnt, 
															LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
															UWORD *src, UWORD *dst )
{
	ULONG	src_color;
	ULONG	dst_word;
	LONG	shifts;

	(void) src_bits;

	src += ( src_bit_offset >> 5 ) << 1;											// points to the first source word
	dst_cnt++;

	if ( line_cnt == 0 )
	{	
		ULONG	*merge_buf;
		
		dst = (UWORD *) ((UCHAR *) dst + dst_length );
		dst = (UWORD *) ((ULONG *) dst - dst_cnt );
		merge_buf = (ULONG *) dst;
		
		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *((ULONG *) src );
			src += 2;
			dst_cnt--;
		}
	}
	else
	{
		UWORD	*merge_buf;
		LONG		i;
		LONG		j;

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (UWORD *) dst;
		dst_cnt += dst_cnt;																			// # of destination pixels

		for ( j = dst_cnt; j > 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP16( src_color );

			*merge_buf++ = ( src_color >> 8 ) & 0x00ff;
			*merge_buf++ = src_color & 0x00ff;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )
		{
			src = (UWORD *) ((UCHAR *) src + src_line_offset );
			merge_buf = dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP16( src_color );

				*merge_buf++ += ( src_color >> 8 ) & 0x00ff;
				*merge_buf++ += src_color & 0x00ff;
			}
		}

		dst = (UWORD *) ((UCHAR *) dst + dst_length );
		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )
		{
			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) *( --merge_buf ) >> shifts;
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 8;

				INTEL_SWAP16( dst_word );
				*( --dst ) = (UWORD) dst_word;
				dst_cnt--;
			}
		}
		else
		{
			line_cnt++;																						// number of lines

			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) ( *( --merge_buf ) / line_cnt );
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 8;

				INTEL_SWAP16( dst_word );
				*( --dst ) = (UWORD) dst_word;		
				dst_cnt--;
			}
		}
	}
	return((ULONG *) dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (16 bits, 2 components, first one is alpha)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_AG16_AG16( LONG line_cnt, LONG dst_cnt, 
															LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
															UWORD *src, UWORD *dst )
{
	ULONG	src_color;
	ULONG	dst_word;

	(void) src_bits;

	src += ( src_bit_offset >> 5 ) << 1;											// points to the first source word
	dst_cnt++;

	if ( line_cnt == 0 )
	{	
		ULONG	*merge_buf;
		
		dst = (UWORD *) ((UCHAR *) dst + dst_length );
		dst = (UWORD *) ((ULONG *) dst - dst_cnt );
		merge_buf = (ULONG *) dst;
		
		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *((ULONG *) src );
			src += 2;
			dst_cnt--;
		}
	}
	else
	{
		ULONG	*merge_buf;
		LONG		i;
		LONG		j;
		ULONG		alpha;

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (ULONG *) dst;
		dst_cnt += dst_cnt;																			// # of destination pixels

		for ( j = dst_cnt; j > 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP16( src_color );

			alpha = ( src_color >> 8 ) & 0x00ff;
			*merge_buf++ = alpha;
			*merge_buf++ = ( src_color & 0x00ff ) * alpha;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )										// add the following lines
		{
			src = (UWORD *) ((UCHAR *) src + src_line_offset );
			merge_buf = (ULONG *) dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP16( src_color );

				alpha = ( src_color >> 8 ) & 0x00ff;
				*merge_buf++ += alpha;
				*merge_buf++ += ( src_color & 0x00ff ) * alpha;
			}
		}

		dst = (UWORD *) ((UCHAR *) dst + dst_length );
		line_cnt++;																						// number of lines

		while ( dst_cnt > 0 )
		{
			merge_buf -= 2;

			alpha = merge_buf[0];																// sum of alphas
			dst_word = ( alpha / line_cnt ) << 8;								// alpha

			if ( alpha )																				// component values different from zero?
				dst_word |= ( merge_buf[1] / alpha );							// gray

			INTEL_SWAP16( dst_word );
			*( --dst ) = (UWORD) dst_word;		
			dst_cnt--;
		}
	}
	return((ULONG *) dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (24 bits, 3 components)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_RGB24_RGB24( LONG line_cnt, LONG dst_cnt, 
																LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
																UCHAR *src, UCHAR *dst )
{
	LONG		shifts;

	(void) src_bits;

	src += src_bit_offset >> 3;																// pointer to the first source pixel
	dst_cnt++;

	if ( line_cnt == 0 )
	{	
		ULONG	*merge_buf;
		
		dst += dst_length - ( dst_cnt << 2 );
		merge_buf = (ULONG *) dst;
		
		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *(ULONG *) src;
			src += 4;
			dst_cnt--;
		}
	}
	else
	{
		UWORD	*merge_buf;
		LONG	i;
		LONG	j;
		
// we have to adjust dst_cnt and src_line_offset because they
// count in 4-byte-words -> convert to 3-byte counter
		src_line_offset += dst_cnt << 2;
		dst_cnt = ( dst_cnt << 2 ) / 3;													// number of destination pixels
		src_line_offset -= dst_cnt + dst_cnt + dst_cnt;					// now the offset to the next source line refers to pixels and not to (quad-)words

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (UWORD *) dst;

		for ( j = dst_cnt; j > 0; j-- )
		{
			*merge_buf++ = *src++;
			*merge_buf++ = *src++;
			*merge_buf++ = *src++;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )										// add the following lines
		{
			src = ((UCHAR *) src + src_line_offset );							// next destination line
			merge_buf = (UWORD *) dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				*merge_buf++ += *src++;
				*merge_buf++ += *src++;
				*merge_buf++ += *src++;
			}
		}

		dst += dst_length;																			// pointer behind the buffer
		dst -= dst_cnt & 1;																			// adjust the address if the number of pixels is odd (means: align the start address)

		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )
		{
			while ( dst_cnt > 0 )
			{
				*( --dst ) = (UCHAR) ( *( --merge_buf ) >> shifts );	// blue
				*( --dst ) = (UCHAR) ( *( --merge_buf ) >> shifts );	// green
				*( --dst ) = (UCHAR) ( *( --merge_buf ) >> shifts );	// red
				dst_cnt--;
			}
		}
		else
		{
			line_cnt++;

			while ( dst_cnt > 0 )
			{
				*( --dst ) = (UCHAR) ( *( --merge_buf ) / line_cnt );	// blue
				*( --dst ) = (UCHAR) ( *( --merge_buf ) / line_cnt );	// green
				*( --dst ) = (UCHAR) ( *( --merge_buf ) / line_cnt );	// red
				dst_cnt--;
			}
		}
	}
	return((ULONG *) dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (32 bits, 3 components ˆ 8 bits)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_xRGB24_xRGB24( LONG line_cnt, LONG dst_cnt, 
																	LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
																	ULONG *src, ULONG *dst )
{
	ULONG	src_color;
	ULONG	dst_word;
	LONG	shifts;

	(void) src_bits;

	src += src_bit_offset >> 5;
	dst_cnt++;

	if ( line_cnt == 0 )
	{	
		ULONG	*merge_buf;
		
		dst = (ULONG *) ((UCHAR *) dst + dst_length );
		dst -= dst_cnt;
		merge_buf = dst;

		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *src++;
			dst_cnt--;
		}
	}
	else
	{
		UWORD	*merge_buf;
		LONG	i;
		LONG	j;

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (UWORD *) dst;

		for ( j = dst_cnt; j > 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP32( src_color );

			*merge_buf++ = 0;
			*merge_buf++ = ( src_color >> 16 ) & 0x000000ffL;
			*merge_buf++ = ( src_color >> 8 ) & 0x000000ffL;
			*merge_buf++ = src_color & 0x000000ffL;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )
		{
			src = (ULONG *) ((UCHAR *) src + src_line_offset );
			merge_buf = (UWORD *) dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP32( src_color );

				merge_buf++;
				*merge_buf++ += ( src_color >> 16 ) & 0x000000ffL;
				*merge_buf++ += ( src_color >> 8 ) & 0x000000ffL;
				*merge_buf++ += src_color & 0x000000ffL;
			}
		}

		dst = (ULONG *) ((UCHAR *) dst + dst_length );

		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )
		{
			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) *( --merge_buf ) >> shifts;					// blue
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 8;		// green
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 16;	// red
				--merge_buf;

				INTEL_SWAP32( dst_word );
				*( --dst ) = dst_word;		
				dst_cnt--;
			}
		}
		else
		{
			line_cnt++;

			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) ( *( --merge_buf ) / line_cnt );					// blue
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 8;		// green
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 16;	// red
				--merge_buf;

				INTEL_SWAP32( dst_word );
				*( --dst ) = dst_word;		
				dst_cnt--;
			}
		}
	}
	return( dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (32 bits, 4 independent components)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_CMYK32_CMYK32( LONG line_cnt, LONG dst_cnt, 
																	LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
																	ULONG *src, ULONG *dst )
{
	ULONG	src_color;
	ULONG	dst_word;
	LONG		shifts;

	(void) src_bits;

	src += src_bit_offset >> 5;																// pointer to the first source word
	dst_cnt++;

	if ( line_cnt == 0 )																			// single line?
	{	
		ULONG	*merge_buf;
		
		dst = (ULONG *) ((UCHAR *) dst + dst_length );
		dst -= dst_cnt;
		merge_buf = dst;

		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *src++;
			dst_cnt--;
		}
	}
	else
	{
		UWORD	*merge_buf;
		LONG		i;
		LONG		j;

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (UWORD *) dst;

		for ( j = dst_cnt; j > 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP32( src_color );

			*merge_buf++ = ( src_color >> 24 ) & 0x000000ffL;
			*merge_buf++ = ( src_color >> 16 ) & 0x000000ffL;
			*merge_buf++ = ( src_color >> 8 ) & 0x000000ffL;
			*merge_buf++ = src_color & 0x000000ffL;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )										// add the following lines
		{
			src = (ULONG *) ((UCHAR *) src + src_line_offset );		// next source line
			merge_buf = (UWORD *) dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP32( src_color );

				*merge_buf++ += ( src_color >> 24 ) & 0x000000ffL;
				*merge_buf++ += ( src_color >> 16 ) & 0x000000ffL;
				*merge_buf++ += ( src_color >> 8 ) & 0x000000ffL;
				*merge_buf++ += src_color & 0x000000ffL;
			}
		}

		dst = (ULONG *) ((UCHAR *) dst + dst_length );

		shifts = cnt_to_shifts[line_cnt];

		if ( shifts >= 0 )
		{
			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) *( --merge_buf ) >> shifts;					// blue
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 8;		// green
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 16;	// red
				dst_word |= ((ULONG) *( --merge_buf ) >> shifts ) << 24;	// alpha

				INTEL_SWAP32( dst_word );
				*( --dst ) = dst_word;		
				dst_cnt--;
			}
		}
		else
		{
			line_cnt++;																						// number of lines

			while ( dst_cnt > 0 )
			{
				dst_word =   (ULONG) ( *( --merge_buf ) / line_cnt );					// blue
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 8;		// green
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 16;	// red
				dst_word |= ((ULONG) ( *( --merge_buf ) / line_cnt )) << 24;	// alpha

				INTEL_SWAP32( dst_word );
				*( --dst ) = dst_word;		
				dst_cnt--;
			}
		}
	}
	return( dst );
}

//----------------------------------------------------------------------------------------
// Merge lines (32 bits, 4 components, first one is alpha)
// Function result:		-
// line_cnt:					number of lines - 1
// dst_cnt:						number of destination words - 1
// src_bits:					bits per source pixel
// src_bit_offset:		bit offset of the first source pixel to the start of line
// src_line_offset:		offset to the next source line in bytes (assumes that [dst_cnt+1]*4 bytes are read) 
// dst_length:				length of the destination buffer in bytes
// src:								source address
// dst:								destination address
//----------------------------------------------------------------------------------------
ULONG	*merge_lines_ARGB32_ARGB32( LONG line_cnt, LONG dst_cnt, 
																	LONG src_bits, LONG src_bit_offset, LONG src_line_offset, LONG dst_length,
																	ULONG *src, ULONG *dst )
{
	ULONG	src_color;
	ULONG	dst_word;

	(void) src_bits;

	src += src_bit_offset >> 5;																// pointer to the first source word
	dst_cnt++;

	if ( line_cnt == 0 )																			// single line?
	{	
		ULONG	*merge_buf;
		
		dst = (ULONG *) ((UCHAR *) dst + dst_length );
		dst -= dst_cnt;
		merge_buf = dst;

		while ( dst_cnt > 0 )
		{
			*merge_buf++ = *src++;
			dst_cnt--;
		}
	}
	else
	{
		ULONG	*merge_buf;
		LONG		i;
		LONG		j;
		ULONG		alpha;

		if ( line_cnt > 255 )
			line_cnt = 255;

		merge_buf = (ULONG *) dst;

		for ( j = dst_cnt; j > 0; j-- )
		{
			src_color = *src++;
			INTEL_SWAP32( src_color );

			alpha = ( src_color >> 24 ) & 0x000000ffL;
			*merge_buf++ = alpha;
			*merge_buf++ = (( src_color >> 16 ) & 0x000000ffL ) * alpha;
			*merge_buf++ = (( src_color >> 8 ) & 0x000000ffL ) * alpha;
			*merge_buf++ = ( src_color & 0x000000ffL ) * alpha;
		}

		for ( i = line_cnt - 1; i >= 0; i-- )										// add the following lines
		{
			src = (ULONG *) ((UCHAR *) src + src_line_offset );		// next source line
			merge_buf = (ULONG *) dst;

			for ( j = dst_cnt; j > 0; j-- )
			{
				src_color = *src++;
				INTEL_SWAP32( src_color );

				alpha = ( src_color >> 24 ) & 0x000000ffL;
				*merge_buf++ += alpha;
				*merge_buf++ += (( src_color >> 16 ) & 0x000000ffL ) * alpha;
				*merge_buf++ += (( src_color >> 8 ) & 0x000000ffL ) * alpha;
				*merge_buf++ += ( src_color & 0x000000ffL ) * alpha;
			}
		}

		dst = (ULONG *) ((UCHAR *) dst + dst_length );
		line_cnt++;																							// number of lines

		while ( dst_cnt > 0 )
		{
			merge_buf -= 4;

			alpha = merge_buf[0];																	// sum of alphas
			dst_word = ( alpha / line_cnt ) << 24;								// alpha

			if ( alpha )																					// component values different from zero?
			{
				dst_word |= ( merge_buf[1] / alpha ) << 16;					// red
				dst_word |= ( merge_buf[2] / alpha ) << 8;					// green
				dst_word |= ( merge_buf[3] / alpha );								// blue
			}

			INTEL_SWAP32( dst_word );
			*( --dst ) = dst_word;		
			dst_cnt--;
		}
	}
	return( dst );
}
