///////////////////////////////////////////////////////////////////////////////
/// @file deGlobalTypes.hpp
///
/// @brief Basic datatype definitions (Destiny-wide scope)
///
/// @author Hootie
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Sept 2001
/// @author Hootie
/// @remarks Rearchitecture II
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DEGLOBALTYPES_HPP
#define DEGLOBALTYPES_HPP

#define _DEQUOTE(x) #x
#define DESTRINGIZE_VALUE(x) _DEQUOTE(x)

#include "deOS.hpp" // platform-specific settings
#include <cstring> // memcpy, strcmp, etc
#include <cstdlib> // malloc & free

// comment this line to make everything become a "float"
#define DE_DOUBLE_PRECISION (1)



//=================================================================================
// Datatypes
//=================================================================================

typedef char deBoolean;
typedef float deFloat;
#ifdef DE_DOUBLE_PRECISION
	typedef double deDouble;
	#define COS cos
	#define SIN sin
	#define TAN tan
	#define ACOS acos
	#define ASIN asin
	#define ATAN atan
#else
	typedef float deDouble;
	#define COS cosf
	#define SIN sinf
	#define TAN tanf
	#define ACOS acosf
	#define ASIN asinf
	#define ATAN atanf
#endif
typedef unsigned long deARGB;
typedef unsigned short	deWorldID;
typedef unsigned long	deObjectID;

// windows types
// from windef.h
typedef unsigned long		DWORD;
typedef int					BOOL;
typedef unsigned char		BYTE;
typedef unsigned short		WORD;
typedef float				FLOAT;
typedef FLOAT*				PFLOAT;
typedef BOOL*				LPBOOL;
typedef BYTE*				LPBYTE;
typedef int*				LPINT;
typedef WORD*				LPWORD;
typedef long*				LPLONG;
typedef DWORD*				LPDWORD;
typedef void*				LPVOID;
typedef const void*			LPCVOID;
typedef int					INT;
typedef unsigned int		UINT;
typedef unsigned int*		PUINT;
// from RpcNdr.h
typedef unsigned char byte;
// from wtypes.h
typedef byte BYTE;
typedef unsigned short WORD;
typedef unsigned int UINT;
typedef int INT;
typedef long LONG;
typedef unsigned long DWORD;
// from somewhere
typedef void * HANDLE;

// "sized" types
typedef signed char         s8;
typedef signed short        s16;
typedef signed long         s32;

typedef unsigned char       u8;
typedef unsigned short      u16;
typedef unsigned long       u32;

// platform-specific types
#ifdef DE3D_HANDLES_ARE_VOID
typedef void * HWND;
typedef void * HINSTANCE;
typedef	void * HMONITOR;
#else
typedef struct HWND__*		HWND;
typedef struct HINSTANCE__*	HINSTANCE;
typedef	struct HMONITOR__*	HMONITOR;
#endif
typedef HINSTANCE HMODULE;

#if defined(DE3D_INT64_IS_LONG_LONG)
typedef signed long long    s64;
typedef unsigned long long  u64;
#elif defined(DE3D_INT64_IS_MS_INT64)
typedef signed __int64		s64;
typedef unsigned __int64    u64;
#endif



//=================================================================================
// Defines and macros
//=================================================================================

const deBoolean DE_TRUE = 1;
const deBoolean DE_FALSE = 0;
#define deTRUE  (DE_TRUE)
#define deFALSE (DE_FALSE)
// Packs individual A,R,G,B values into a combined ARGB DWORD
#define ARGB(a,r,g,b) \
    ((DWORD)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
#define GrabARGB(argb,a,r,g,b)\
	{a=((argb>>24)&0xff); r=((argb>>16)&0xff); g=((argb>>8)&0xff); b=((argb)&0xff); }

#define deXOR(x,y) ( (!(x)&&(y)) || ((x)&&!(y)) )

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

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

#define LEAK_HUNTING  // comment out to disable leak-hunts
#ifndef __GNUC__
#ifdef LEAK_HUNTING
 #ifdef _DEBUG
   //#pragma message("leak-hunting enabled")
  #define _CRTDBG_MAP_ALLOC 
  #include <crtdbg.h>
  #undef malloc
  #define new				new(_NORMAL_BLOCK,__FILE__, __LINE__)
  #define malloc(s)		_malloc_dbg(s,_NORMAL_BLOCK,__FILE__,__LINE__)
  #define realloc(p, s)	_realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
  #define free(p)			_free_dbg(p, _NORMAL_BLOCK)
 #endif // _DEBUG
#endif
#endif

#if defined(_MSC_VER) && 0
// make MSVC use standard 'for' layout - will generate lots of warning 4127 on W4 mode
#define for if(0){}else for
#endif

// stupid windows stuff
#undef FAR
#define FAR

#define DETAILED_DEBUG_REPORT (1)
#define NOTIFY_BAD_RETURNS (1)

#if defined(DETAILED_DEBUG_REPORT) && DETAILED_DEBUG_REPORT && defined(_DEBUG) && !defined(__GNUC__)
#if defined(NOTIFY_BAD_RETURNS) && NOTIFY_BAD_RETURNS
#define _DEBUG_RETURN_LEVEL		_CRT_ASSERT
#else  // NOTIFY_BAD_RETURNS
#define _DEBUG_RETURN_LEVEL		_CRT_WARN
#endif // NOTIFY_BAD_RETURNS
#include <crtdbg.h>
//#include <winbase.h>
static inline void BREAK_EXECUTION() {_asm{int 3}}
#define DEBUGMSG0(msg)						if (1 == _CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL, "%s\n", msg)) BREAK_EXECUTION()
#define DEBUGMSG1(fmt,arg1)					if (1 == _CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL, fmt"\n", arg1)) BREAK_EXECUTION()
#define DEBUGMSG2(fmt,arg1,arg2)			if (1 == _CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL, fmt"\n", arg1, arg2)) BREAK_EXECUTION()
#define DEBUGMSG3(fmt,arg1,arg2,arg3)		if (1 == _CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL, fmt"\n", arg1, arg2, arg3)) BREAK_EXECUTION()
#define DEBUGMSG4(fmt,arg1,arg2,arg3,arg4)	if (1 == _CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL, fmt"\n", arg1, arg2, arg3, arg4)) BREAK_EXECUTION()
#define DEBUGRETURN(retval,message)			if (1 == _CrtDbgReport(_DEBUG_RETURN_LEVEL, __FILE__, __LINE__, NULL, "WARNING\n%s\nRETURNING %s\n", message, #retval))\
											{BREAK_EXECUTION();return retval;} else return retval
#define DEBUGRETURNNOVAL(message)			if (1 == _CrtDbgReport(_DEBUG_RETURN_LEVEL, __FILE__, __LINE__, NULL, "WARNING\n%s\nRETURNING void\n", message))\
											{BREAK_EXECUTION();return;} else return
#define DEBUG_EXP_RETURN(exp,retval)		if (exp) {} else if (1 == _CrtDbgReport(_DEBUG_RETURN_LEVEL, __FILE__, __LINE__, NULL, "%s\nRETURNING %s\n", #exp, #retval))\
											{BREAK_EXECUTION();return retval;} else return retval
#define DEBUG_EXP_RETURNMSG(exp,retval,msg)	if (exp) {} else if (1 == _CrtDbgReport(_DEBUG_RETURN_LEVEL, __FILE__, __LINE__, NULL, "%s\nMESSAGE:\n%s\nRETURNING %s\n", #exp, msg, #retval))\
											{BREAK_EXECUTION();return retval;} else return retval
#define DE_ASSERT(exp)						if (exp) {} else if (1 != _CrtDbgReport(_DEBUG_RETURN_LEVEL, __FILE__, __LINE__, NULL, "%s", #exp)) {} else BREAK_EXECUTION()
#define DEBUG_ONLY(exp)						exp
#else  // DETAILED_DEBUG_REPORT
static inline void BREAK_EXECUTION() {}
#define DEBUGMSG0(msg)
#define DEBUGMSG1(fmt,arg1)
#define DEBUGMSG2(fmt,arg1,arg2)
#define DEBUGMSG3(fmt,arg1,arg2,arg3)
#define DEBUGMSG4(fmt,arg1,arg2,arg3,arg4)
#define DEBUGRETURN(retval,message)			return retval
#define DEBUGRETURNNOVAL(message)			return
#define DEBUG_EXP_RETURN(exp,retval)
#define DEBUG_EXP_RETURNMSG(exp,retval,msg)
#define DE_ASSERT(exp)
#define DEBUG_ONLY(exp)
#endif // DETAILED_DEBUG_REPORT

//=================================================================================
// Enums
//=================================================================================

enum deResult
{
	deFAILED = 0,
	deSUCCEEDED,
	deCRITICALERROR,
	_deResult_Force32bit = 0x7fffffff
};



//=================================================================================
// Structures
//=================================================================================

/// base reference-counting interface for all Destiny3D classes
//class IdeRefCountBase
DE3D_INTERFACE_(IdeRefCountBase)
{
protected:
	virtual ~IdeRefCountBase() {}
public:
	/// increment the object's reference count
	/// @return The new reference count
	virtual s32 Claim() = 0;
	/// decrement the object's reference count, causing destruction if it reaches 0
	/// @return The new reference count
	virtual s32 Release() = 0;
};
struct deIDPair
{
	deWorldID	wid;
	deObjectID	oid;
};
struct deVec3d 
{
	union	{ deDouble x; deDouble X; };
	union	{ deDouble y; deDouble Y; };
	union	{ deDouble z; deDouble Z; };
//	deVec3d() {}
//	deVec3d(deDouble x_, deDouble y_, deDouble z_) : x(x_),y(y_),z(z_) {}
};
struct deVec3f
{
	union { deFloat x; deFloat X; };
	union { deFloat y; deFloat Y; };
	union { deFloat z; deFloat Z; };
//	deVertex() {}
//	deVertex(deFloat x_, deFloat y_, deFloat z_) : x(x_),y(y_),z(z_) {}
//	explicit deVertex(const deVec3d & vec) : x((deFloat)vec.x), y((deFloat)vec.y), z((deFloat)vec.z) {}
};
typedef deVec3f deVertex;
struct deColor
{
	deFloat r,g,b,a;
//	deColor() {}
//	deColor(deFloat r_, deFloat g_, deFloat b_, deFloat a_) : r(r_),g(g_),b(b_),a(a_) {}
};
struct deRect
{
	long Left;
	long Top;
	long Right;
	long Bottom;
//	deRect() {}
//	deRect(const long left_, const long top_, const long right_, const long bottom_)
//		: Left(left_),Top(top_),Right(right_),Bottom(bottom_) {}
};
struct deFloatRect
{
	deFloat Top;
	deFloat Left;
	deFloat Bottom;
	deFloat Right;
//	deFloatRect() {}
//	deFloatRect(const deFloat left_, const deFloat top_, const deFloat right_, const deFloat bottom_)
//		: Left(left_),Top(top_),Right(right_),Bottom(bottom_) {}
};
struct dePlane
{
	deVec3d Norm;
	deDouble Dist;
//	dePlane() {}
//	dePlane(const deVec3d & norm_, const deDouble& dist_)
//		: Norm(norm_),Dist(dist_) {}
};
struct deBoundSphere
{
	deVec3d Center;
	deDouble Radius;
//	deBoundSphere() {}
//	deBoundSphere(const deVec3d & center_, const deDouble& radius_)
//		: Center(center_),Radius(radius_) {}
};
struct deAABB
{
	deVec3d Min;
	deVec3d Max;
//	deAABB() {}
//	deAABB(const deVec3d & min_, const deVec3d& max_)
//		: Min(min_),Max(max_) {}
};
struct deOBB
{
	deVec3d Corner;
	deVec3d Offset[3];
};
struct deTexCoord1
{
	deFloat u;
//	deTexCoord1() {}
//	deTexCoord1(deFloat u_) : u(u_) {}
};
struct deTexCoord2
{
	deFloat u;
	deFloat v;
/*	deTexCoord2() {}
	deTexCoord2(deFloat u_, deFloat v_) : u(u_),v(v_) {}
	const deTexCoord2& operator=(const deTexCoord1 & tex1) { u = tex1.u; v = 0; }
	operator deTexCoord1() {return deTexCoord1(u);}
	*/
};
struct deTexCoord3
{
	deFloat u;
	deFloat v;
	deFloat w;
/*	deTexCoord3() {}
	deTexCoord3(deFloat u_, deFloat v_, deFloat w_) : u(u_),v(v_),w(w_) {}
	explicit deTexCoord3(const deVertex& vec) : u(vec.x),v(vec.y),w(vec.z) {}
	explicit deTexCoord3(const deVec3d& vec) : u((deFloat)vec.x),v((deFloat)vec.y),w((deFloat)vec.z) {}
	const deTexCoord3& operator=(const deTexCoord1 & tex1) { u = tex1.u; v = 0; w = 0;}
	const deTexCoord3& operator=(const deTexCoord2 & tex2) { u = tex2.u; v = tex2.v; w = 0; }
	operator deTexCoord1() {return deTexCoord1(u);}
	operator deTexCoord2() {return deTexCoord2(u, v);}
	*/
};
struct deTexCoord4
{
	deFloat u;
	deFloat v;
	deFloat w;
	deFloat t;
/*	deTexCoord4() {}
	deTexCoord4(deFloat u_, deFloat v_, deFloat w_, deFloat t_) : u(u_),v(v_),w(w_),t(t_) {}
	const deTexCoord4& operator=(const deTexCoord1 & tex1) { u = tex1.u; v = 0; w = 0; t = 0; }
	const deTexCoord4& operator=(const deTexCoord2 & tex2) { u = tex2.u; v = tex2.v; w = 0; t = 0; }
	const deTexCoord4& operator=(const deTexCoord3 & tex3) { u = tex3.u; v = tex3.v; w = tex3.w; t = 0; }
	operator deTexCoord1() {return deTexCoord1(u);}
	operator deTexCoord2() {return deTexCoord2(u, v);}
	operator deTexCoord3() {return deTexCoord3(u, v, w);}
	*/
};
/*
struct deTexCoord
{
	union { deFloat u; deFloat U; };
	union { deFloat v; deFloat V; };
};
*/
typedef deTexCoord2 deTexCoord;
struct deLVert
{
	deVec3d Pos;
	deVec3d Norm;
	deColor Color;
	deTexCoord UV;
};

// helper implementation, not to be used in public interfaces
class deRefCountBase : virtual public IdeRefCountBase
{
private:
	s32 m_NumClaims;
protected:
	deRefCountBase() : m_NumClaims(1) {}
	virtual ~deRefCountBase() {}
public:
	s32 Claim()
	{	++m_NumClaims; 
		return m_NumClaims;
	}
	s32 Release()
	{	--m_NumClaims;
		if (m_NumClaims == 0)
		{	delete this;
			return 0;
		}
		return m_NumClaims;
	}
};


//=================================================================================
// Constants
//=================================================================================
const deDouble DE_PI = (deDouble)3.14159265358979323846;
const deDouble DE_ONEOVERPI = (deDouble)0.318309886183790671;
const deVec3d deZeroVec = {0,0,0};
const deVec3d deOneVec = {1,1,1};
const deVec3d deVecX = {1,0,0};
const deVec3d deVecY = {0,1,0};
const deVec3d deVecZ = {0,0,1};
const deTexCoord deZeroTex = {0,0};

//=================================================================================
// Conversions
//=================================================================================
#pragma warning (disable : 4244)
static inline deColor deMake_Color(deARGB in) { deColor ret = {((in>>16)&0xFF)/255.0f, ((in>>8)&0xFF)/255.0f, (in&0XFF)/255.0f, ((in>>24)&0xFF)/255.0f}; return ret;}
static inline deARGB deMake_Color(deColor &in) { deARGB ret = ((deARGB(in.a*255))<<24) | ((deARGB(in.r*255))<<16) | ((deARGB(in.g*255))<<8) | ((deARGB(in.b*255))); return ret; }
static inline deVec3d deMake_Vec3d(deDouble x, deDouble y, deDouble z) {deVec3d ret = {x,y,z}; return ret;}
static inline deVec3d deMake_Vec3d(const deVertex & vec) {deVec3d ret = {vec.x,vec.y,vec.z}; return ret;}
static inline deVertex deMake_Vertex(deFloat x, deFloat y, deFloat z) {deVertex ret = {x,y,z}; return ret;}
static inline deVertex deMake_Vertex(const deVec3d & vec) {deVertex ret = {(deFloat)vec.x,(deFloat)vec.y,(deFloat)vec.z}; return ret;}
static inline deTexCoord deMake_TexCoord(deFloat u_, deFloat v_) { deTexCoord ret = {u_, v_}; return ret; }
static inline void deMake_TexCoord(deTexCoord1& target, const deTexCoord2& tex2) { target.u = tex2.u; }
static inline void deMake_TexCoord(deTexCoord1& target, const deTexCoord3& tex3) { target.u = tex3.u; }
static inline void deMake_TexCoord(deTexCoord1& target, const deTexCoord4& tex4) { target.u = tex4.u; }
static inline void deMake_TexCoord(deTexCoord2& target, const deTexCoord1& tex1) { target.u = tex1.u; target.v = 0; }
static inline void deMake_TexCoord(deTexCoord2& target, const deTexCoord3& tex3) { target.u = tex3.u; target.v = tex3.v; }
static inline void deMake_TexCoord(deTexCoord2& target, const deTexCoord4& tex4) { target.u = tex4.u; target.v = tex4.v; }
static inline void deMake_TexCoord(deTexCoord3& target, const deTexCoord1& tex1) { target.u = tex1.u; target.v = 0; target.w = 0; }
static inline void deMake_TexCoord(deTexCoord3& target, const deTexCoord2& tex2) { target.u = tex2.u; target.v = tex2.v; target.w = 0; }
static inline void deMake_TexCoord(deTexCoord3& target, const deTexCoord4& tex4) { target.u = tex4.u; target.v = tex4.v; target.w = tex4.w; }
static inline void deMake_TexCoord(deTexCoord4& target, const deTexCoord1& tex1) { target.u = tex1.u; target.v = 0; target.w = 0; target.t = 0; }
static inline void deMake_TexCoord(deTexCoord4& target, const deTexCoord2& tex2) { target.u = tex2.u; target.v = tex2.v; target.w = 0; target.t = 0; }
static inline void deMake_TexCoord(deTexCoord4& target, const deTexCoord3& tex3) { target.u = tex3.u; target.v = tex3.v; target.w = tex3.w; target.t = 0; }
#pragma warning (default : 4244)

//=================================================================================
// Useful macros
//=================================================================================
#define DEG2RAD(d) ((d)*(DE_PI/180.0))
#define RAD2DEG(r) ((r)*(180*DE_ONEOVERPI))

#define DE3D_SAFE_DELETE(p)       if(!p) {} else delete (p);     (p)=NULL
#define DE3D_SAFE_DELETE_ARRAY(p) if(!p) {} else delete[] (p);   (p)=NULL
#define DE3D_SAFE_RELEASE(p)      if(!p) {} else (p)->Release(); (p)=NULL

// comment these two lines to adjust message output on compilation
#define _TODO
#define _PRINT_NOTES
#ifdef _TODO
	#define __DE_FILE__LINE__ __FILE__ "(" DESTRINGIZE_VALUE(__LINE__) "): "

	#define TODO(x) message(__DE_FILE__LINE__"\n"\
			"+--------------------------------\n"\
			"| TODO : " #x                   "\n"\
			"+--------------------------------\n")
	#define FIXME(x) message(__DE_FILE__LINE__"\n"\
			"+--------------------------------\n"\
			"| FIXME: " #x                   "\n"\
			"+--------------------------------\n")

	#ifdef _PRINT_NOTES
		#define note(x) message(__DE_FILE__LINE__ "NOTE: " #x "\n")
	#else
		#define note(x) _BLANK_PRAGMA
	#endif
	#define todo(x)  message(__DE_FILE__LINE__ "TODO: " #x "\n")
	#define fixme(x) message(__DE_FILE__LINE__ "FIXME: " #x "\n")
#else
	#define _BLANK_PRAGMA
	#define TODO(x) _BLANK_PRAGMA
	#define FIXME(x) _BLANK_PRAGMA
	#define note(x) _BLANK_PRAGMA
	#define todo(x) _BLANK_PRAGMA
	#define fixme(x) _BLANK_PRAGMA
#endif


#endif //End DEGLOBALTYPES_HPP

