//	MiscHelper.h - Various helpful bits and pieces.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	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/>.
//	----------------------------------------------------------------------------

#ifndef MISCHELPER_H_
#define MISCHELPER_H_

#include <cmath>

///	Used to try and force the compiler to inline functions.
#ifdef WIN32
#define strictinline __forceinline
#elif defined (__GNUC__)
#define strictinline inline __attribute__((always_inline))
#else
#define strictinline inline
#endif

///	Definition of PI.
#define NIALL_PI 3.1415926535897932384626433832795f

///	Cheap fake log approximation.
strictinline float fakeLog(float val)
{
	const float logCoeff = 1.0f - (1.0f/0.75f);

	return val/(val + (logCoeff*(val-1.0f)));
}

///	Cheap fake exp approximation.
strictinline float fakeExp(float val)
{
	const float expCoeff = 1.0f - (1.0f/0.1f);

	return val/(val + (expCoeff*(val-1.0f)));
}

///	Cheap fake sine approximation.
/*!
	Taken from:
	http://devmaster.net/forums/topic/4648-fast-and-accurate-sinecosine/

	TODO: Still need to test this is good enough.
 */
strictinline float fakeSine(float val)
{
	const float B = 4.0f/NIALL_PI;
	const float C = -4.0f/(NIALL_PI * NIALL_PI);
	const float P = 0.225f;
	
	float retval = B * val + C * val * std::abs(val);
	
	retval = P * (retval * std::abs(retval) - retval) + retval;

	return retval;
};

///	Rounding function.
strictinline int round(float val)
{
	int retval;

	retval = (int)val;
	if((val-(float)retval) > 0.5f)
		++retval;

	return retval;
}

///	Helper method to test whether a number is a power-of-two.
strictinline bool isPowerOfTwo(int val)
{
	int tempint = 1;
	bool retval = false;

	//Surely there's a better way to do this?
	while(tempint < val)
		tempint *= 2;

	if(tempint == val)
		retval = true;

	return retval;
};

///	Helper method to return the next highest number that is a power-of-two.
/*!
	\return if val is already power-of-two, it will be returned as-is.
	*/
strictinline int powerOfTwo(int val)
{
	int retval = 1;

	while(retval < val)
		retval *= 2;

	return retval;
};

#endif
