/*-
 * Copyright (c) 1999,2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of the source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Any redistribution solely in binary form must conspicuously
 *    reproduce the following disclaimer in documentation provided with the
 *    binary redistribution.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'', WITHOUT ANY WARRANTIES, EXPRESS
 * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  LICENSOR SHALL
 * NOT BE LIABLE FOR ANY LOSS OR DAMAGES RESULTING FROM THE USE OF THIS
 * SOFTWARE, EITHER ALONE OR IN COMBINATION WITH ANY OTHER SOFTWARE.
 * 
 * 	$Id: maths.h,v 1.35 2000/06/06 14:40:30 anselm Exp $
 */

#ifndef __maths_h__
#define __maths_h__

#include        <math.h>

#define MATHS_BEGIN	namespace Maths {
#define MATHS_END	};

#ifdef _MSC_VER
// Remove warnings generated by broken export on templates
#pragma warning(disable : 4251) // class needs dll export
#pragma warning(disable : 4275) // export class derived from non-export
#pragma warning(disable : 4786) // truncated debug info
#endif

#include "linkage.h"

MATHS_BEGIN

#ifdef q_ps2
#define acosf(x) ((float) acos(x))
#define atan2f(x,y) ((float) atan2(x,y))
#define atanf(x) ((float) atan(x))
#define powf(x,y) ((float) pow(x,y))
#define floorf(x) ((float) floor(x))

#define min(a,b)	((a) < (b)? (a):(b))
#endif


// 'Standard' error bounds.
static const float Epsilon = 0.001f;

static const float PI = 3.1415926536f;

// Supplementary maths functions
EXPORT_QMATHS double invSqrt(double v);// inverse sqrt
EXPORT_QMATHS float invSqrtf(float v);	// inverse sqrt
EXPORT_QMATHS float fastInvSqrtf(float v); // fast (less accurate) inverse sqrt

// some processors have faster smaller ways of doing this
inline float sincosf(float &rcos, float theta)
{
    rcos = cosf(theta); return(sinf(theta));
}
inline double sincos(double &rcos, double theta)
{
    rcos = cos(theta); return(sin(theta));
}


// You might think that this could be an inline function. You would be wrong.
// VC5 is so stupid that it can't see that the argument is always a constant
//.and ends up generating a call to some truly fantastic code. Utterly
// pointless.

#if defined(__alpha__) || (defined(__GNUC__) && defined(__i386__))
#define twopow(n) (double)(1ULL << (n))
#else
#define twopow(n) ((n) >= 32						 \
		   ? ((double)(1UL << ((n) - 32))) * (65536.0 * 65536.0) \
		   : (double)(1UL << (n)))
#endif

// Convert a float to fixed point with a default precision of 8.
inline int
floatToFixed(float f, unsigned int prec)
{
#ifdef __alpha__
    return (int)(f * (1 << prec));
#else
    volatile double tmp = (volatile double)f + 4294967296.0 + twopow(52 - prec);
    return *(volatile int *)&tmp;
#endif
}

inline int
floatToFixed(float f)
{
#ifdef __alpha__
    return (int)(f * 256);
#else
    volatile double tmp = (double)f + 17596481011712.0;
    return *(volatile int *)&tmp;
#endif
}

inline float
fixedToFloat(int i, unsigned int prec)
{
#ifdef __alpha__
    return (float)i / (1 << prec);
#else
    volatile double tmp = 4294967296.0 + twopow(52 - prec);
    *(volatile int *)&tmp = i;
    return (float)(tmp - 4294967296.0 - twopow(52 - prec));
#endif
}

#undef twopow

inline float
fixedToFloat(int i)
{
#ifdef __alpha__
    return (float)i / 256;
#else
    volatile double tmp = 17596481011712.0;
    *(volatile int *)&tmp = i;
    return (float)(tmp - 17596481011712.0);
#endif
}

// Return the sign bit of a float.  Returns 1 if the float is negative,
// otherwise zero.
inline int
floatToSign(float f)
{
    unsigned int i = *(unsigned int *) &f; // assumes ieee format
    return i >> 31;
}

// Return the sign bit of a float.  Returns ~0 if the float is negative,
// otherwise zero.
inline int
floatToMask(float f)
{
    float g = f;
    int i = *(int *)&g;	// assumes ieee format
    return i >> 31;
}

inline int
intToMask(int i)
{
    return i >> 31;
}

inline int
floatToIntBits(float f)
{
    return *(volatile int *)(&f);
}   

inline float
intBitsToFloat(int i)
{
    return *(volatile float*)(&i);
}

inline bool
floatIsNegative(float f)
{
    unsigned int i = *(unsigned int *) &f; // assumes ieee format
    return (i >> 31) != 0;
}

inline bool
floatIsPositive(float f)
{
    unsigned int i = *(unsigned int *) &f; // assumes ieee format
    return (i >> 31) == 0;
}

// Comparison functions with error ranges.
inline bool
equals(float a, float b, float e = Epsilon)
{
    //return fabsf(a - b) <= e;

    return floatToMask(e - fabsf(a - b)) == 0;
}

inline bool
lessThan(float a, float b, float e = Epsilon)
{
    //return (b - a) >= e;

    return (floatToMask(b - a - e) == 0);
}

inline bool
greaterThan(float a, float b, float e = Epsilon)
{
    //return (a - b) >= e;

    return (floatToMask(a - b - e) == 0);
}

inline int
lessEqual(float a, float b, float e = Epsilon)
{
    return lessThan(a, b, e) || equals(a, b, e);
}

inline bool
greaterEqual(float a, float b, float e = Epsilon)
{
    return greaterThan(a, b, e) || equals(a, b, e);
}

inline int
compare(float a, float b, float e = Epsilon)
{
    return (equals(a, b, e) ? 0 : (lessThan(a, b, e) ? -1 : 1));
}

inline bool
absGreater(float a, float b)
{
    return(fabsf(a) > b);
}

inline bool
absLess(float a, float b)
{
    return(fabsf(a) < b);
}

// common flags constants for transform matrices

struct TransformFlags
{
    enum Flags {
        Identity        = 0x000,
        Translate       = 0x001,
        Rotate          = 0x002,
        UniformScale    = 0x004,
        Scale           = 0x008,
        Shear           = 0x010,
        General         = 0x020
    };
};


MATHS_END

#include "vec2.h"
#include "vec3.h"
#include "vec4.h"
#include "quat4.h"
#include "matrix3.h"
#include "matrix4.h"
#include "affine4.h"
#include "plane4.h"
#include "box2.h"
#include "box3.h"
#include "sphere3.h"
#include "cylinder3.h"
#include "ray.h"
#include "color4b.h"

#endif

// Local Variables:
// mode: c++
// End:
