/*******************************************/
/*                                         */
/* colors.cpp                              */
/*                                         */
/* scol colors primitives                  */
/*                                         */
/* Loïc Berthelot, CryoNetworks, june 2002 */
/*                                         */
/*******************************************/


/*
extern "C" {
#include "../kernel/include/kernel.h"
}
//#include "../kernel/mmemory.h"
#include "../kernel/mainscol.h"
#include "../kernel/macros.h"
#include "../kernel/loadpak.h" 
*/
extern "C" {
#include "x/scolplugin.h"
}
#include "colors.h"
#include "macros.h"





// Matrix of conversions op.

typedef int (*ColorOp) (mmachine,int);

static ColorOp _convertMat[COLOR_NB_MODE][COLOR_NB_MODE];



///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// list of operations                                                        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////


//
//identity
//
int _COLOR_CONVERT_IDENTITY (mmachine m, int value) { return value; }



//
// separate RGB
//
void _COLOR_I_TO_BGR (int color, unsigned char *b, unsigned char *g, unsigned char *r)
{
	*b = (color>>16) &0xFF;
	*g = (color>>8) &0xFF;
	*r = color & 0xFF;
}

void _COLOR_I16_TO_BGR (int color, unsigned char *b, unsigned char *g, unsigned char *r)
{
	*b = (color>>7) &0xF8;
	*g = (color>>2) &0xF8;
	*r = (color<<3) &0xF8;
}

//
// assemble RGB
//
int _COLOR_BGR_TO_I (unsigned char b, unsigned char g, unsigned char r) 
{
	return ( ((b <<16) & 0xFF0000)  |  ((g <<8) & 0xFF00)  |  (r & 0xFF) );
}


int _COLOR_BGR_TO_I15 (unsigned char b, unsigned char g, unsigned char r)
{
	return ( ((b <<7) &0x7C00)  |  ((g <<2) &0x03E0)  |  (r>>3 &0x1F) );
}



//
// 16, 24 bits conversions
//
int _COLOR_CONVERT_16_24 (mmachine m, int value) { return ( ((value<<9) &0xF80000) | ((value<<6) &0xF800) | ((value<<3) &0xF8) );}

int _COLOR_CONVERT_24_16 (mmachine m, int value) { return ( ((value>>9) &0x7C00) | ((value>>6) &0x03E0) | ((value>>3) &0x1F) );}

int _COLOR_CONVERT_RGB_BGR_16 (mmachine m, int value) { return ( ((value>>10) &0x1F) | (value &0x03E0) | ((value<<10) &0x7C00) );}

int _COLOR_CONVERT_RGB_BGR_24 (mmachine m, int value) { return ( ((value>>16) &0xFF) | (value &0xFF00) | ((value<<16) &0xFF0000) );}

int _COLOR_CONVERT_RGB24_BGR16 (mmachine m, int value) { return ( ((value>>19) &0x1F) | ((value>>6) &0x03E0) | ((value <<7) &0x7C00) ); } 

int _COLOR_CONVERT_RGB16_BGR24 (mmachine m, int value) { return ( ((value>>7) &0xF8) | ((value<<6) &0xF800) | ((value<<19) &0xF80000) );}



//
// get a RGB24 color from a palette 
//
int _COLOR_GET_RGB24_FROM_8 (mmachine m, int value)
{
unsigned int * tab;
int palette = MMget(m, 0);


    if ( palette == NIL ) 
	{
		MMechostr(1, "\n!! _color_convert : 8 bits conversions need a 256 RGB palette !!\n");
		return -1;
	}
	palette >>=1;
    if ( MMsize(m, palette) != 768)
    {
        MMechostr ( 1 , "\n!! _color_convert : The Palette Array haven't the good size (need a 256 RGB palette <=> 768 values)!!\n" ) ;
        return -1;
    }

    tab = (unsigned int *) MMstart(m, palette);

	return ( ((tab[value*3]<<15) &0xFF0000) | ((tab[(value*3)+1]<<7) &0xFF00) | ((tab[(value*3)+2]>>1) & 0xFF));
}



//
// get 8 bits color from a palette and R G B values
//
// first, the test is done with the eight bits of each values, 
// and if no result is found, the test is done with the five most significant bits (rgb values from 15 bits color)
//
int _COLOR_GET_8_FROM_RGB (mmachine m, unsigned int r, unsigned int g, unsigned int b)
{
unsigned int * tab;
int palette = MMget(m, 0);
int i;

    if ( palette == NIL ) 
	{
		MMechostr(1, "\n!! _color_convert : 8 bits conversions need a 256 RGB palette !!\n");
		return -1;
	}
	palette >>=1;
    if ( MMsize(m, palette) != 768)
    {
        MMechostr ( 1 , "\n!! _color_convert : The Palette Array haven't the good size (need a 256 RGB palette <=> 768 values)!!\n" ) ;
        return -1;
    }

    tab = (unsigned int *) MMstart(m, palette);

	for (i=0; i < 768; i+=3)
		if ((r == (tab[i]>>1)) && (g == (tab[i+1]>>1)) && (b == (tab[i+2]>>1)))
			return (i/3);

	for (i=0; i < 768; i+=3)
		if ( ((r &0xF8) == ((tab[i]>>1) &0xF8)) && ((g &0xF8) == ((tab[i+1]>>1) &0xF8)) && ((b &0xF8) == ((tab[i+2]>>1) &0xF8)) )
			return (i/3);

	MMechostr(1, "\n!! _color_convert : couldn't find ant correspondance between the color value and the palette given as parameter!!\n");

	return 0;
}



//
// 8 bits conversions
//

int _COLOR_CONVERT_8_RGB16 (mmachine m, int value) 
{
int color;

	if ((color = _COLOR_GET_RGB24_FROM_8 (m, value)) == -1)
		return -1;
	
	return _COLOR_CONVERT_24_16 (m, color);
}


int _COLOR_CONVERT_8_RGB24 (mmachine m, int value) 
{
	return _COLOR_GET_RGB24_FROM_8 (m, value);
}


int _COLOR_CONVERT_8_BGR16 (mmachine m, int value) 
{
int color;

	if ((color = _COLOR_GET_RGB24_FROM_8 (m, value)) == -1)
		return -1;
	
	return _COLOR_CONVERT_RGB24_BGR16 (m, color);
}


int _COLOR_CONVERT_8_BGR24 (mmachine m, int value) 
{
int color;

	if ((color = _COLOR_GET_RGB24_FROM_8 (m, value)) == -1)
		return -1;
	
	return _COLOR_CONVERT_RGB_BGR_24 (m, color);
}


int _COLOR_CONVERT_RGB16_8 (mmachine m, int value) 
{
unsigned char r, g, b;
int color = _COLOR_CONVERT_16_24 (m, value);

	_COLOR_I_TO_BGR (color, &b, &g, &r);

	return _COLOR_GET_8_FROM_RGB (m, r, g, b);
}



int _COLOR_CONVERT_RGB24_8 (mmachine m, int value) 
{
unsigned char r, g, b;

	_COLOR_I_TO_BGR (value, &b, &g, &r);

	return _COLOR_GET_8_FROM_RGB (m, r, g, b);
}



int _COLOR_CONVERT_BGR16_8 (mmachine m, int value) 
{
unsigned char r, g, b;
int color = _COLOR_CONVERT_RGB16_BGR24 (m, value);

	_COLOR_I_TO_BGR (color, &b, &g, &r);

	return _COLOR_GET_8_FROM_RGB (m, r, g, b);
}



int _COLOR_CONVERT_BGR24_8 (mmachine m, int value) 
{
unsigned char r, g, b;
int color = _COLOR_CONVERT_RGB_BGR_24 (m, value);

	_COLOR_I_TO_BGR (color, &b, &g, &r);

	return _COLOR_GET_8_FROM_RGB (m, r, g, b);
}










/***********************************************************************************/
/*                                                                                 */
/* _color_convert                                                                  */
/*                                                                                 */
/* fun [I value   I from_mode    I to_mode    tab I palette]     I converted_value */
/*                                                                                 */
/***********************************************************************************/
int _color_convert (mmachine m)
{
int to_mode   = MTOI (MMget(m, 1));
int from_mode = MTOI (MMget(m, 2));
int value     = MTOI (MMget(m, 3));
int res;


	if ((to_mode == NIL) || (from_mode == NIL) || (value == NIL)) return -1;

	if (((res = _convertMat[from_mode][to_mode] (m, value))) < 0) return -1;

	SEDROP(m, 3);
	MMset (m, 0, res<<1);
	return 0;
}





/***********************************************************************************/
/*                                                                                 */
/* _color_init                                                                     */
/*                                                                                 */
/* initialize the matrix of operations                                             */
/*                                                                                 */
/***********************************************************************************/
void _color_init ()
{

	_convertMat[COLOR_8][COLOR_8]         = _COLOR_CONVERT_IDENTITY;
	_convertMat[COLOR_8][COLOR_RGB16]     = _COLOR_CONVERT_8_RGB16;
	_convertMat[COLOR_8][COLOR_RGB24]     = _COLOR_CONVERT_8_RGB24;
	_convertMat[COLOR_8][COLOR_BGR16]     = _COLOR_CONVERT_8_BGR16;
	_convertMat[COLOR_8][COLOR_BGR24]     = _COLOR_CONVERT_8_BGR24;

	_convertMat[COLOR_RGB16][COLOR_8]     = _COLOR_CONVERT_RGB16_8;
	_convertMat[COLOR_RGB16][COLOR_RGB16] = _COLOR_CONVERT_IDENTITY;
	_convertMat[COLOR_RGB16][COLOR_RGB24] = _COLOR_CONVERT_16_24;
	_convertMat[COLOR_RGB16][COLOR_BGR16] = _COLOR_CONVERT_RGB_BGR_16;
	_convertMat[COLOR_RGB16][COLOR_BGR24] = _COLOR_CONVERT_RGB16_BGR24;

	_convertMat[COLOR_RGB24][COLOR_8]     = _COLOR_CONVERT_RGB24_8;
	_convertMat[COLOR_RGB24][COLOR_RGB16] = _COLOR_CONVERT_24_16;
	_convertMat[COLOR_RGB24][COLOR_RGB24] = _COLOR_CONVERT_IDENTITY;
	_convertMat[COLOR_RGB24][COLOR_BGR16] = _COLOR_CONVERT_RGB24_BGR16;
	_convertMat[COLOR_RGB24][COLOR_BGR24] = _COLOR_CONVERT_RGB_BGR_24;

	_convertMat[COLOR_BGR16][COLOR_8]     = _COLOR_CONVERT_BGR16_8;
	_convertMat[COLOR_BGR16][COLOR_RGB16] = _COLOR_CONVERT_RGB_BGR_16;
	_convertMat[COLOR_BGR16][COLOR_RGB24] = _COLOR_CONVERT_RGB16_BGR24;
	_convertMat[COLOR_BGR16][COLOR_BGR16] = _COLOR_CONVERT_IDENTITY;
	_convertMat[COLOR_BGR16][COLOR_BGR24] = _COLOR_CONVERT_16_24;

	_convertMat[COLOR_BGR24][COLOR_8]     = _COLOR_CONVERT_BGR24_8;
	_convertMat[COLOR_BGR24][COLOR_RGB16] = _COLOR_CONVERT_RGB24_BGR16;
	_convertMat[COLOR_BGR24][COLOR_RGB24] = _COLOR_CONVERT_RGB_BGR_24;
	_convertMat[COLOR_BGR24][COLOR_BGR16] = _COLOR_CONVERT_24_16;
	_convertMat[COLOR_BGR24][COLOR_BGR24] = _COLOR_CONVERT_IDENTITY;
}















/************************************************************************************************/
//                                                                                              //
// L O A D    C O L O R S    P A C K A G E                                                      //
//                                                                                              //
/************************************************************************************************/



#define COLORSpkg 6

char * COLORSname [ COLORSpkg ] = 
{
	"COLOR_8",
	"COLOR_RGB16",
	"COLOR_RGB24",
	"COLOR_BGR16",
	"COLOR_BGR24",
	"_color_convert"
} ; 

char * COLORStype [ COLORSpkg ] = 
{
	"I",
	"I",
	"I",
	"I",
	"I",
	"fun [I I I tab I] I"
} ;

int COLORSarg [ COLORSpkg ] = 
{
	TYPVAR,
	TYPVAR,
	TYPVAR,
	TYPVAR,
	TYPVAR,
	4
} ;

int (*COLORSfun[COLORSpkg])(mmachine m)= 
{
	(int (__cdecl *)(struct Mmachine*))(COLOR_8<<1),
	(int (__cdecl *)(struct Mmachine*))(COLOR_RGB16<<1),
	(int (__cdecl *)(struct Mmachine*))(COLOR_RGB24<<1),
	(int (__cdecl *)(struct Mmachine*))(COLOR_BGR16<<1),
	(int (__cdecl *)(struct Mmachine*))(COLOR_BGR24<<1),
	_color_convert
} ;                                                                   


extern "C"
{
int SCOLloadCOLORS(mmachine m)
{
	int k;
	_color_init ();
	k=PKhardpak(m,"COLORS.pkg", COLORSpkg, COLORSname, COLORSfun, COLORSarg, COLORStype);

	return k;
}
}





