/* Copyright (C) 2000 Damir Zucic */

/*=============================================================================

				color_shifts.c

Purpose:
	Prepare left and right color shift for RGB color components. Each
	color component (red, green and blue) must be shifted properly to
	prepare the pixel value for a given RGB triplet.  Every component
	should be shifted first to the right, to remove unused bits, then
	to the left,  to put the remaining bits into the proper position.
	This function prepares  the shifts for all three  RGB components.
	Shifts are used later to prepare colors  for drawing.  Masks from
	XVisualInfo structure (part of GUIS structure) are used as input.

Input:
	(1) Pointer to GUIS structure.  Input data are there; output data
	    will be stored to the same structure.

Output:
	(1) Data added to GUIS structure.
	(2) Return value.

Return value:
	(1) Positive on success.
	(2) Negative on failure.

=============================================================================*/

#include <stdio.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#include "defines.h"
#include "typedefs.h"

/*======function prototypes:=================================================*/

void		ErrorMessage_ (char *, char *, char *,
			       char *, char *, char *, char *);

/*======prepare color shifts:================================================*/

int PrepareColorShifts_ (GUIS *guiSP)
{
XColor		colorS;
int		color_component_size, pixel_value_size;
unsigned long	mask, lowest_bit_mask = 1;
int		lowest_bit_position, highest_bit_position, bitsN;
int		i;

/* Prepare the color component size int bits (16 expected): */
color_component_size = 8 * sizeof (colorS.red);

/* Prepare the pixel value size in bits (32 expected): */
pixel_value_size = 8 * sizeof (colorS.pixel);

/*---------------------------------------------------------------------------*/

/* Find the shifts for red color component: */

/** Check the red mask: **/
if (guiSP->visual_infoS.red_mask == 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Red mask equal to zero!\n", "", "", "");
	return -1;
	}

/** The least significant bit position: **/
mask = guiSP->visual_infoS.red_mask;
lowest_bit_position = -1;
for (i = 0; i < pixel_value_size; i++)
	{
	if ((mask >> i) & lowest_bit_mask)
		{
		lowest_bit_position = i;
		break;
		}
	}

/** Check was it found at all: **/
if (lowest_bit_position < 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Unable to find the lowest bit position",
		       " in the red mask!\n", "", "");
	return -2;
	}

/** The most significant bit position: **/
mask = guiSP->visual_infoS.red_mask;
highest_bit_position = lowest_bit_position;
for (i = lowest_bit_position; i < pixel_value_size; i++)
	{
	if (!((mask >> i) & lowest_bit_mask)) break;
	highest_bit_position = i;
	}

/** Prepare the shifts: **/
bitsN = highest_bit_position - lowest_bit_position + 1;
guiSP->red_right_shift  = color_component_size - bitsN;
guiSP->red_left_shift = lowest_bit_position;

/*---------------------------------------------------------------------------*/

/* Find the shifts for green color component: */

/** Check the green mask: **/
if (guiSP->visual_infoS.green_mask == 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Green mask equal to zero!\n", "", "", "");
	return -3;
	}

/** The least significant bit position: **/
mask = guiSP->visual_infoS.green_mask;
lowest_bit_position = -1;
for (i = 0; i < pixel_value_size; i++)
	{
	if ((mask >> i) & lowest_bit_mask)
		{
		lowest_bit_position = i;
		break;
		}
	}

/** Check was it found at all: **/
if (lowest_bit_position < 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Unable to find the lowest bit position",
		       " in the green mask!\n", "", "");
	return -4;
	}

/** The most significant bit position: **/
mask = guiSP->visual_infoS.green_mask;
highest_bit_position = lowest_bit_position;
for (i = lowest_bit_position; i < pixel_value_size; i++)
	{
	if (!((mask >> i) & lowest_bit_mask)) break;
	highest_bit_position = i;
	}

/** Prepare the shifts: **/
bitsN = highest_bit_position - lowest_bit_position + 1;
guiSP->green_right_shift  = color_component_size - bitsN;
guiSP->green_left_shift = lowest_bit_position;

/*---------------------------------------------------------------------------*/

/* Find the shifts for blue color component: */

/** Check the blue mask: **/
if (guiSP->visual_infoS.blue_mask == 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Blue mask equal to zero!\n", "", "", "");
	return -5;
	}

/** The least significant bit position: **/
mask = guiSP->visual_infoS.blue_mask;
lowest_bit_position = -1;
for (i = 0; i < pixel_value_size; i++)
	{
	if ((mask >> i) & lowest_bit_mask)
		{
		lowest_bit_position = i;
		break;
		}
	}

/** Check was it found at all: **/
if (lowest_bit_position < 0)
	{
	ErrorMessage_ ("garlic", "PrepareColorShifts_", "",
		       "Unable to find the lowest bit position",
		       " in the blue mask!\n", "", "");
	return -6;
	}

/** The most significant bit position: **/
mask = guiSP->visual_infoS.blue_mask;
highest_bit_position = lowest_bit_position;
for (i = lowest_bit_position; i < pixel_value_size; i++)
	{
	if (!((mask >> i) & lowest_bit_mask)) break;
	highest_bit_position = i;
	}

/** Prepare the shifts: **/
bitsN = highest_bit_position - lowest_bit_position + 1;
guiSP->blue_right_shift  = color_component_size - bitsN;
guiSP->blue_left_shift = lowest_bit_position;

/*---------------------------------------------------------------------------*/

/* Return positive value on success: */
return 1;
}

/*===========================================================================*/


