/*
**	Command & Conquer Red Alert(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	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, see <http://www.gnu.org/licenses/>.
*/

/* $Header: g:/library/source/rcs/./lib.c 1.16 1994/05/20 15:34:33 joe_bostic Exp $ */
/***************************************************************************
 **   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ***************************************************************************
 *                                                                         *
 *                 Project Name : Library Routines                         *
 *                                                                         *
 *                    File Name : LIB.C                                    *
 *                                                                         *
 *                   Programmer : Scott Bowen                              *
 *                                                                         *
 *                   Start Date : January 14, 1993                         *
 *                                                                         *
 *                  Last Update : May 20, 1993   [PWG]                     *
 *                                                                         *
 *-------------------------------------------------------------------------*
 * Functions:                                                              *
 *   Add_Long_To_Pointer -- Pointer arithmatic when pointer could be XMS.  *
 *   Find_Argv -- Checks to see if string is in arguement              		*
 *   Mono_Mem_Dump -- Dumps memory to mono monitor with hex and char.      *
 *   Convert_HSV_To_RGB -- Converts HSV cordinates to RGB values           *
 *   Convert_RGB_To_HSV -- Converts RGB to RSV coordinates.                *
 *   Set_Search_Drives -- Sets up the CDRom and HardDrive paths.           *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


#include <dos.h>
#include <stdio.h>
#include <string.h>
#include "misc.h"

//PRIVATE unsigned Divide_With_Round(unsigned num, unsigned den);


/***************************************************************************
 * Divide_With_Round -- Divides integers and round to nearest integer.     *
 *                                                                         *
 * INPUT:         int numberator.                                         *
 *                int denominator.                                        *
 *                                                                         *
 * OUTPUT:        Returns value rounded.                                   *
 *                                                                         *
 * WARNINGS:                                                               *
 *                                                                         *
 * HISTORY:                                                                *
 *   02/13/1992  SB : Created.                                             *
 *=========================================================================*/
static unsigned Divide_With_Round(unsigned num, unsigned den)
{
	// return num/den + (0 ro 1).  1 if the remainder is more than half the denominator.
	return( (num / den) + (unsigned)((num % den) >= ((den + 1) >> 1)) );
}

#define HSV_BASE 255 // This is used to get a little better persion on HSV conversion.
#define RGB_BASE 63  // Not 64, this is really the max value.


/***************************************************************************
 * Convert_RGB_To_HSV -- Converts RGB to RSV coordinates.                  *
 *                                                                         *
 * INPUT:      int r,g, and b values.                                     *
 *             int *h, *s, and *v pointers.                              	*
 *                                                                         *
 * OUTPUT:     Assigns values to *h, *s, and *v.                           *
 *                                                                         *
 * WARNINGS:   The reason we use a different base for HSV then RGB is      *
 *             because we loose alot of persision by not using floating    *
 *             point.  Using the same base value (63) made it so that      *
 *             about 50% of the time one RGB value would be one different  *
 *             then the original if you went from RGB to HSV to RGB.       *
 *             Using 255 drop it down to about 9% of the time we get an    *
 *             off value.  To get it perfect, we would have to make the    *
 *             HSV base larger - but then you need to do all calculations  *
 *             in long instead of unsigned int.                                   *
 * HISTORY:                                                                *
 *   02/11/1992  SB : Created.                                             *
 *=========================================================================*/
void Convert_RGB_To_HSV(unsigned int r, unsigned int g, unsigned int b, unsigned int *h, unsigned int *s, unsigned int *v)
{
 	unsigned int m, r1, g1, b1, tmp;

	// Convert RGB base to HSV base.
	r = Divide_With_Round((r * HSV_BASE), RGB_BASE);
	g = Divide_With_Round((g * HSV_BASE), RGB_BASE);
	b = Divide_With_Round((b * HSV_BASE), RGB_BASE);

	// Set hue to default.
	*h = 0;

	// Set v = Max(r,g,b) to find dominant primary color.
	*v = (r > g) ? r : g;
	if (b > *v) *v = b;

	// Set m = min(r,g,b) to find amount of white.
	m = (r < g) ? r : g;
	if (b < m) m = b;

	// Determine the normalized saturation.
	if (*v != 0) {
		*s = Divide_With_Round( (*v - m) * HSV_BASE ,*v);
	} else {
		*s = 0;
	}

	if (*s != 0) {
		tmp = *v - m;
	 	r1 = Divide_With_Round( (*v - r) * HSV_BASE, tmp);
	 	g1 = Divide_With_Round( (*v - g) * HSV_BASE, tmp);
	 	b1 = Divide_With_Round( (*v - b) * HSV_BASE, tmp);

		// Find effect of second most predominant color.
		// In which section of the hexagon of colors does the color lie?
		if ((*v) == r) {
		 	if (m == g) {
				*h = 5 * HSV_BASE + b1;
			} else {
				*h = 1 * HSV_BASE - g1;
			}
		} else {
			if ((*v) == g) {
			 	if (m == b) {
					*h = 1 * HSV_BASE + r1;
				} else {
					*h = 3 * HSV_BASE - b1;
				}
			} else {
				// *v == b
			 	if (m == r) {
					*h = 3 * HSV_BASE + g1;
				} else {
					
					*h = 5 * HSV_BASE - r1;
				}
			}
		}

		// Divide by six and round.
		*h = Divide_With_Round(*h, 6);
	}
}

/***************************************************************************
 * Convert_HSV_To_RGB -- Converts HSV cordinates to RGB values             *
 *                                                                         *
 * INPUT:      int h,s, and v coordinates                                 *
 *             int *r, *g, and *b pointers.                              	*
 *                                                                         *
 * OUTPUT:     Assigns values to *r, *g, and *b.                           *
 *                                                                         *
 * WARNINGS:                                                               *
 *                                                                         *
 * HISTORY:                                                                *
 *   02/11/1992  SB : Created.                                             *
 *=========================================================================*/
void Convert_HSV_To_RGB(unsigned int h, unsigned int s, unsigned int v, unsigned int *r, unsigned int *g, unsigned int *b)
{
	unsigned int i;				// Integer part.
	unsigned int f;				// Fractional or remainder part.  f/HSV_BASE gives fraction.
	unsigned int tmp;			// Tempary variable to help with calculations.
	unsigned int values[7];	// Possible rgb values.  Don't use zero.


	h *= 6;
	f = h % HSV_BASE;

	// Set up possible red, green and blue values.
	values[1] =	
	values[2] = v;

	//
	// The following lines of code change 
	//	values[3] = (v * (HSV_BASE - ( (s * f) / HSV_BASE) )) / HSV_BASE;
	//	values[4] = values[5] = (v * (HSV_BASE - s)) / HSV_BASE;
	// values[6] = (v * (HSV_BASE - (s * (HSV_BASE - f)) / HSV_BASE)) / HSV_BASE;
	// so that the are rounded divides.
	//

	tmp = Divide_With_Round(s * f, HSV_BASE);
	values[3] = Divide_With_Round(v * (HSV_BASE - tmp), HSV_BASE);

	values[4] = 
	values[5] = Divide_With_Round(v * (HSV_BASE - s), HSV_BASE);

	tmp = HSV_BASE - Divide_With_Round(s * (HSV_BASE - f),  HSV_BASE);
	values[6] = Divide_With_Round(v * tmp, HSV_BASE);


	// This should not be rounded.
	i = h / HSV_BASE;

	i += (i > 4) ? -4 : 2;
	*r = Divide_With_Round(values[i] * RGB_BASE, HSV_BASE);

	i += (i > 4) ? -4 : 2;
	*b = Divide_With_Round(values[i] * RGB_BASE, HSV_BASE);

	i += (i > 4) ? -4 : 2;
	*g = Divide_With_Round(values[i] * RGB_BASE, HSV_BASE);
} 
