/**
                                                                          
	@file:	r2d_i.c
	
	@author Christophe Favergeon                              
                                                                          
    @version	0.5	

    Purpose:	Low level utilities functions for R2D 
	
*/

/*
																			
 	Date       	Modification												
  ------------------------------------									
    06/02/2001	Create		
	10/18/2001  Version 0.5 for first integration with Riviera database
																											    
																			
 (C) Copyright 2001 by Texas Instruments Incorporated, All Rights Reserved
*/



#include "rv/general.h"
#include "rvf/rvf_api.h"
#include "r2d/r2d_config.h"
#include "r2d/r2d.h"
#include "r2d/r2d_i.h"
#include "r2d/r2d_independance_layer.h"
#if (R2D_DEBUG == R2D_ON)
#include <stdio.h>
#endif

#if (R2D_EMBEDDED_LCD == R2D_PC_COLOR_LCD)
#include "Windows.h"
#endif


////////////////////////////////////////
//
//    GLOBALS
//

UINT32 *r2d_g_dithering_matrix;

#if (R2D_ASM == R2D_ON)
T_RVF_MUTEX * r2d_g_blit_mutex;
T_R2D_DRAWING_MODE r2d_g_old_mode;
R2D_BOOLEAN r2d_g_old_use_foreground;
INT32 r2d_g_old_srcdst;
UINT32 r2d_g_old_foreground_pixelvalue;
UINT32 r2d_g_old_background_pixelvalue;
#endif

T_RVF_MUTEX * r2d_g_global_mutex;


////////////////////////////////////////
//
// Class definitions
//

const T_R2D_CLASS_SHAPE r2d_class_rectangle=
{
   NULL,
   r2d_release_rectangle,
   r2d_draw_rectangle_shape,
   r2d_fill_rectangle_shape,
   r2d_clone_rectangle_shape,
   r2d_translate_rectangle_shape,
   r2d_point_in_rectangle_shape
};

const T_R2D_CLASS_SHAPE r2d_class_circle=
{
   NULL,
   r2d_release_circle,
   r2d_draw_circle_shape,
   r2d_fill_circle_shape,
   r2d_clone_circle_shape,
   r2d_translate_point_shape,
   r2d_point_in_circle_shape
};

const T_R2D_CLASS_SHAPE r2d_class_ellipse=
{
   NULL,
   r2d_release_ellipse,
   r2d_draw_ellipse_shape,
   r2d_fill_ellipse_shape,
   r2d_clone_rectangle_shape,
   r2d_translate_rectangle_shape,
   r2d_point_in_ellipse_shape
};

const T_R2D_CLASS_SHAPE r2d_class_round_rectangle=
{
   NULL,
   r2d_release_round_rectangle,
   r2d_draw_round_rectangle_shape,
   r2d_fill_round_rectangle_shape,
   r2d_clone_round_rectangle_shape,
   r2d_translate_rectangle_shape,
   r2d_point_in_round_rectangle_shape
};

const T_R2D_CLASS_SHAPE r2d_class_arc=
{
   NULL,
   r2d_release_arc,
   r2d_draw_arc_shape,
   r2d_fill_arc_shape,
   r2d_clone_arc_shape,
   r2d_translate_rectangle_shape,
   r2d_point_in_not_supported_shape
};

const T_R2D_CLASS_SHAPE r2d_class_text=
{
   NULL,
   r2d_release_text,
   r2d_draw_text_shape,
   r2d_fill_text_shape,
   r2d_clone_text_shape,
   r2d_translate_point_shape,
   r2d_point_in_not_supported_shape
};

//////////////////////////////////
//
//  All globals must be protected
// with semaphores


T_R2D_FRAMEBUFFER* r2d_g_framebuffer;

// Pointer for default initializations of graphical context
T_R2D_FRAMEBUFFER *r2d_g_default_font_framebuffer;
INT32 *r2d_g_default_font_metrics;
INT32 *r2d_g_default_font_table;


BOOLEAN r2d_g_event_was_sent;
INT16 r2d_g_refresh_disabled;

T_R2D_FONT_DESCRIPTION *r2d_g_font_configuration;

//////////////////////////////////
//
// Common C code
//

T_R2D_DRAWING_OP r2d_get_drawing_op(T_R2D_GC *gc,T_R2D_DRAWING_MODE mode)
{
	if (((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind!=R2D_FULL_KIND)
	{
		return(r2d_g_lcd_operators[mode]);
	}
	else
        return(r2d_g_color_operators[mode]);
}

#if (R2D_ASM == R2D_ON)
UINT32 * r2d_get_asm_drawing_op(T_R2D_GC *gc,T_R2D_DRAWING_MODE mode)
{
	if (((T_R2D_FRAMEBUFFER*)(gc->p_frame_buffer))->kind!=R2D_FULL_KIND)
	{
		return(r2d_g_asm_lcd_operators[mode]);
	}
	else
        return(r2d_g_asm_color_operators[mode]);
}
#endif


// Get max component
UINT16 r2d_max_color(UINT16 red,UINT16 green, UINT16 blue)
{
   UINT16 result=red;
   if (green > result)
     result=green;
   if (blue > result)
     result=blue;
   return(result);
}

// Get min component
UINT16 r2d_min_color(UINT16 red,UINT16 green, UINT16 blue)
{
   UINT16 result=red;
   if (green < result)
     result=green;
   if (blue < result)
     result=blue;
   return(result);
}

#if (R2D_DITHERING == R2D_ON)

// Set element (x,y) of dithering or dithered matrix
void r2d_set_dithering_matrix_entry(UINT32 *matrix,UINT32 elem,INT16 x,INT16 y)
{
   UINT32 *p=matrix;
   p+=(x&1)+(y&1)*2;
   *p=elem;
}


#else
#define r2d_set_dithering_matrix_entry(matrix,elem,x,y)
#endif


static UINT32 r2d_color_copy_operator(UINT32 old,UINT32 value)
{
	return(value);
}
static UINT32 r2d_color_or_operator(UINT32 old,UINT32 value)
{
	if ((value&0x00FFFFFF)==0)
		return(value);
	else
	    return(old);
	
}
static UINT32 r2d_color_and_operator(UINT32 old,UINT32 value)
{
	return(old & value);
}
static UINT32 r2d_color_xor_operator(UINT32 old,UINT32 value)
{
	return(old ^ value) ;
}
static UINT32 r2d_color_not_copy_operator(UINT32 old,UINT32 value)
{
	return(~value);
}
static UINT32 r2d_color_not_or_operator(UINT32 old,UINT32 value)
{
	return(~(old | value));
}
static UINT32 r2d_color_not_and_operator(UINT32 old,UINT32 value)
{
	return(~(old & value));
}
static UINT32 r2d_color_not_xor_operator(UINT32 old,UINT32 value)
{
	return(~(old ^ value)) ;
}

static UINT32 r2d_color_erase_operator(UINT32 old,UINT32 value)
{
	if ((value & 0xFFFFFF)==0xFFFFFF)
		return(0);
	else
		return(old);
}

UINT32 r2d_color_alpha_operator(UINT32 old,UINT32 value)
{
	INT16 a,rs,gs,bs,rd,gd,bd;

			   a=(value >> 24) & 0x0FF;

			   value=~value;
			   old=~old;
			   
			   bs=(value & 0xFF);
			   value=value>>8;
			   gs=(value & 0xFF);
			   value=value>>8;
			   rs=(value & 0xFF);
			   value=value>>8;

			   
			   

			   bd=(old & 0xFF);
			   old=old>>8;
			   gd=(old & 0xFF);
			   old=old>>8;
			   rd=(old & 0xFF);
			   
			   // Pixel value has been complemented before being
			   // saved so that the white correspond to 0 and be
			   // compatible with formulas for other modes.
			   // But alpha value is not complemented
			   // So a=0xFF correspond tranparency
			   bd=((a)*bd+(0x100 - a)*bs) >> 8;
			   gd=((a)*gd+(0x100 - a)*gs) >> 8;
			   rd=((a)*rd+(0x100 - a)*rs) >> 8;

			   old=0;
			   old=old|(rd&0xFF);
			   old=old<<8;
               old=old|(gd&0xFF);
			   old=old<<8;
			   old=old|(bd&0xFF);
			   old=(~old) & 0x00FFFFFF;
			   return(old);
}


const T_R2D_DRAWING_OPERATORS r2d_g_color_operators=
{
   &r2d_color_copy_operator,
   &r2d_color_or_operator,
   &r2d_color_and_operator,
   &r2d_color_xor_operator,
   &r2d_color_not_copy_operator,
   &r2d_color_not_or_operator,
   &r2d_color_not_and_operator,
   &r2d_color_not_xor_operator,
   &r2d_color_alpha_operator,
   &r2d_color_erase_operator
};

void r2d_convert_foreground_color_color(T_R2D_GC *gc,UINT32 color)
{
	UINT32 lcolor;
	gc->foreground_pixel_value=r2d_alpha(color);
    gc->foreground_pixel_value<<=24;

	lcolor=0;
	lcolor|=r2d_red(color);
	lcolor=lcolor<<8;
	lcolor|=r2d_green(color);
	lcolor=lcolor<<8;
	lcolor|=r2d_blue(color);
	
    gc->foreground_pixel_value|=(~lcolor) & 0x00FFFFFF;
    
     
}

// Return the pixel value to write on the LCD or the offscreen
// pixmap
// LCD DEPENDENT
void r2d_convert_background_color_color(T_R2D_GC *gc,UINT32 color)
{
	UINT32 lcolor;
    gc->background_pixel_value=r2d_alpha(color);
    gc->background_pixel_value<<=24;

    lcolor=0;
	lcolor|=r2d_red(color);
	lcolor=lcolor<<8;
	lcolor|=r2d_green(color);
	lcolor=lcolor<<8;
	lcolor|=r2d_blue(color);
	

    gc->background_pixel_value|=(~color) & 0x00FFFFFF;
     
}


// Select pixel of a color framebuffer as being
// a foreground or background one
BOOLEAN r2d_color_framebuffer_foreground_pixel(UINT32 lcd_value,T_R2D_GC_PTR src_gc)
{
   if ((lcd_value & 0x00FFFFFF))
    return(TRUE);
   else
    return(FALSE);
}


INT32 r2d_ptree_find(INT32 *tree,INT32 unicode)
{
    INT32 state=0;
    INT32 current_block;

    current_block=unicode>>R2D_PTREE_SHIFT;
    while (tree[state+R2D_PTREE_TYPE]!=R2D_PTREE_T_LEAF)
    {
      if (current_block & tree[state+R2D_PTREE_PREFIX])
        state=tree[state+R2D_PTREE_RIGHT]; 
      else
        state=tree[state+R2D_PTREE_LEFT]; 
    }
    
    if (tree[state+R2D_PTREE_UNICODE_BLOCK]==current_block)
    { 
         return(unicode + (tree[state+R2D_PTREE_CONVERSION]));
    }
    else 
         return(0); 
}



INT32 r2d_get_point_side(INT16 x,INT16 y,INT32 sa,INT32 sb)
{
	INT32 ret;
	ret=((sb>>1)*x+((-sa)>>1)*y);
   return(ret);
}

BOOLEAN r2d_check_is_in_arc_region(INT16 x,INT16 y,T_R2D_ARC_REGION *rgn)
{
	INT32 a,b;

	a=r2d_get_point_side(x,y,rgn->sa,rgn->sb);
	b=r2d_get_point_side(x,y,rgn->ea,rgn->eb);

	/*if (a&&b)
		r2d_set_foreground_color_with_argb(r2d_g_lcd_gc,0,255,0,0);
	else if (!a && !b)
        r2d_set_foreground_color_with_argb(r2d_g_lcd_gc,0,0,255,0);
	else if (!a && b)
        r2d_set_foreground_color_with_argb(r2d_g_lcd_gc,0,0,0,255);
	else if (a && !b)
        r2d_set_foreground_color_with_argb(r2d_g_lcd_gc,0,255,255,0);*/

	if (rgn->one_sector==0)
	  return(((a>=0) && (b>=0)));
	else
	  return(!(!(a>=0) && !(b>=0)));

}

void r2d_arc_region_y_reflect(T_R2D_ARC_REGION *rgn)
{
   rgn->sa=-rgn->sa;
   rgn->ea=-rgn->ea;
}

void r2d_arc_region_x_reflect(T_R2D_ARC_REGION *rgn)
{
   rgn->sb=-rgn->sb;
   rgn->eb=-rgn->eb;
}

void r2d_arc_region_diagonal_reflect(T_R2D_ARC_REGION *rgn)
{
    INT32 tmp;

	tmp=rgn->sa;
	rgn->sa=rgn->sb;
	rgn->sb=tmp;

    tmp=rgn->ea;
	rgn->ea=rgn->eb;
	rgn->eb=tmp;
}