/*****************************************************************************/
// Copyright 2006-2008 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_1d_table.cpp#1 $ */ 
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */

/*****************************************************************************/

#include "dng_1d_table.h"

#include "dng_1d_function.h"
#include "dng_memory.h"
#include "dng_utils.h"

/*****************************************************************************/

dng_1d_table::dng_1d_table ()

	:	fBuffer ()
	,	fTable  (NULL)
	
	{
	
	}

/*****************************************************************************/

dng_1d_table::~dng_1d_table ()
	{
	
	}
	
/*****************************************************************************/

void dng_1d_table::SubDivide (const dng_1d_function &function,
							  uint32 lower,
							  uint32 upper,
							  real32 maxDelta)
	{
	
	uint32 range = upper - lower;
		
	bool subDivide = (range > (kTableSize >> 8));
	
	if (!subDivide)
		{
		
		real32 delta = Abs_real32 (fTable [upper] - 
								   fTable [lower]);
								   
		if (delta > maxDelta)
			{
			
			subDivide = true;
			
			}
		
		}
		
	if (subDivide)
		{
		
		uint32 middle = (lower + upper) >> 1;
		
		fTable [middle] = (real32) function.Evaluate (middle * (1.0 / (real64) kTableSize));
		
		if (range > 2)
			{
			
			SubDivide (function, lower, middle, maxDelta);
			
			SubDivide (function, middle, upper, maxDelta);
			
			}
	
		}
		
	else
		{
		
		real64 y0 = fTable [lower];
		real64 y1 = fTable [upper];
		
		real64 delta = (y1 - y0) / (real64) range;
		
		for (uint32 j = lower + 1; j < upper; j++)
			{
			
			y0 += delta;
				
			fTable [j] = (real32) y0;
						
			}
		
		}
		
	}
	
/*****************************************************************************/

void dng_1d_table::Initialize (dng_memory_allocator &allocator,
							   const dng_1d_function &function,
							   bool subSample)
	{
	
	fBuffer.Reset (allocator.Allocate ((kTableSize + 2) * sizeof (real32)));
	
	fTable = fBuffer->Buffer_real32 ();
	
	if (subSample)
		{
		
		fTable [0         ] = (real32) function.Evaluate (0.0);
		fTable [kTableSize] = (real32) function.Evaluate (1.0);
		
		real32 maxDelta = Max_real32 (Abs_real32 (fTable [kTableSize] -
												  fTable [0         ]), 1.0f) *
						  (1.0f / 256.0f);
							   
		SubDivide (function,
				   0,
				   kTableSize,
				   maxDelta);
		
		}
		
	else
		{
			
		for (uint32 j = 0; j <= kTableSize; j++)
			{
			
			real64 x = j * (1.0 / (real64) kTableSize);
			
			real64 y = function.Evaluate (x);
			
			fTable [j] = (real32) y;
			
			}
			
		}
		
	fTable [kTableSize + 1] = fTable [kTableSize];
	
	}

/*****************************************************************************/

void dng_1d_table::Expand16 (uint16 *table16) const
	{
	
	real64 step = (real64) kTableSize / 65535.0;
	
	real64 y0 = fTable [0];
	real64 y1 = fTable [1];
	
	real64 base  = y0 * 65535.0 + 0.5;
	real64 slope = (y1 - y0) * 65535.0;
	
	uint32 index = 1;
	real64 fract = 0.0;
	
	for (uint32 j = 0; j < 0x10000; j++)
		{
		
		table16 [j] = (uint16) (base + slope * fract);
		
		fract += step;
		
		if (fract > 1.0)
			{
			
			index += 1;
			fract -= 1.0;
			
			y0 = y1;
			y1 = fTable [index];
			
			base  = y0 * 65535.0 + 0.5;
			slope = (y1 - y0) * 65535.0;
			
			}
		
		}
	
	}

/*****************************************************************************/