#ifndef V_TYPES_H
#define V_TYPES_H

/*
 * Limits.
 */
#if     !defined(MAXCHAR)
#define	MAXCHAR							(0x7F)
#define	MINCHAR							(0x80)
#endif  /* !MAXCHAR */
#if     !defined(MAXSHORT)
#define	MAXSHORT						0x7FFF
#define	MINSHORT						0x8000
#endif  /* !MAXSHORT */
#if     !defined(MAXLONG)
#define MAXLONG							(0x7FFFFFFF)
#define MINLONG							(0x80000000)
#endif  /* !MAXLONG */
#if     !defined(MAXLONGLONG) && !defined(INT64BROKEN)
#define MAXLONGLONG						0x7FFFFFFFFFFFFFFF
#define MINLONGLONG						0x8000000000000000
#endif  /* MAXLONGLONG */
#if     !defined(MAXFLOAT)
#define MAXFLOAT						((float)(3.4e+38))
#endif  /* MAXFLOAT */
#if     !defined(MAXDOUBLE)
#define MAXDOUBLE						((double)(1.7e+308))
#endif  /* MAXDOUBLE */

#ifndef	CONFIG_DOUBLEVEC
#define	MAXVEC							MAXFLOAT
#else
#define	MAXVEC							MAXDOUBLE
#endif	/* CONFIG_DOUBLEVEC */

/*
 * Upper limit for estimated fp round-off error (and for square of error)
 */
#ifndef	FLOAT_ZERO_EPSILON
#define	FLOAT_ZERO_EPSILON				((vec_t)(1e-10))
#endif	/* FLOAT_ZERO_EPSILON */
#ifndef	FLOAT_ZERO_EPSILON_SQUARE
#define	FLOAT_ZERO_EPSILON_SQUARE		((vec_t)(1e-20))
#endif	/* FLOAT_ZERO_EPSILON_SQUARE */

/*
 * Base LibV types.
 */
typedef unsigned char			u8_t,	*u8_p;
typedef signed char				s8_t,	*s8_p;
typedef unsigned short			u16_t,	*u16_p;
typedef signed short			s16_t,	*s16_p;
typedef unsigned long			u32_t,	*u32_p;
typedef signed long				s32_t,	*s32_p;
#ifndef	INT64BROKEN
#if		!defined(__UNIX__) && !defined(__CYGWIN32__)
typedef unsigned __int64		u64_t,	*u64_p;
typedef signed __int64			s64_t,	*s64_p;
#else
typedef unsigned long long int	u64_t,	*u64_p;
typedef long long int			s64_t,	*s64_p;
#endif	/* __UNIX__ */
#endif	/* INT64BROKEN */

/*
 * LibV replacement for size_t and ssize_t
 */
typedef unsigned	vsize_t;
typedef int			vssize_t;

/*
 * Pointers: void and string.
 * Note: char_t may be either signed (most platforms) or unsigned.
 */
typedef		void				void_t,	*void_p, **void_pp;
typedef		char				char_t, *char_p, **char_pp;

/*
 * One of the base types: The Handle. Represents most of LibV objects.
 */
typedef		void_p				vhandle_t;

/*
 * There are no handle tables; handles are pointers.
 */
#define		LIBV_INVALID_HANDLE	NULL

/*
 * Another one boolean type
 */
#if			defined(__WATCOMC__) && !defined(__cplusplus)
/*
 * The most elegant way.
 * But it seems that only wcc386 can eat it without side effects.
 */ 
typedef		enum 				{false = 0, true = 1}	vboolean;
#else		/* !defined(__WATCOMC__) || defined(__cplusplus) */
typedef 	int					vboolean;
#define 	false				0
#define 	true				1
#endif		/* !defined(__cplusplus) && defined(__WATCOMC__) */

/*
 * Base floating-point scalar type.
 * Names of type and macro stolen from Id's Quake.
 */
#ifdef		CONFIG_DOUBLEVEC
typedef		double				vec_t, *vec_p;
#else		/* !CONFIG_DOUBLEVEC */
typedef		float				vec_t, *vec_p;
#endif		/* CONFIG_DOUBLEVEC  */

/*
 * Vector and matrix types (low-order).
 * Values in matrices stored in row-major order (OpenGL-unlike)
 */
typedef vec_t					vec2_t[2];
typedef vec_t					vec3_t[3];
typedef vec_t					vec4_t[4];
typedef vec_t					matrix2_t[2][2];
typedef vec_t					matrix3_t[3][3];
typedef vec_t					matrix4_t[4][4];
typedef vec_t					matrix3x4_t[3][4];

/*
 * 24- & 32-bit RGBA colors.
 */
typedef u8_t					color3b_t[3];
typedef u8_t					color4b_t[4];

/*
 * Handy macros for making powers of 2.
 * TODO: move them to other file.
 */

/* Returns 1 if value is power of 2; otherwise returns 0 */
#define IS_POWER_TWO(x)			(((x) & ((x)-1)) ? 0 : 1)

/*
 * Aligns u32_t 'src', so:
 *	a) dst>=src;
 *	b) least 'zero_bits' in 'dst' set to zero.
 * For expample, if 'zero_bits' is 2: 0->0; {1,2,3,4}->4; etc.
 * 'dst' and 'src' can be the same.
 */

#define	ALIGN_UP(dst,src,zero_bits) { \
		u32_t set_bits=(1<<(zero_bits))-1; \
		(dst)=((src)+set_bits)&(0xFFFFFFFF-set_bits); }

/* Based on Quake's net_loop.c::IntAlign */
#define	INT_ALIGN(value) \
		(((value) + (sizeof(int) - 1)) & (~(sizeof(int) - 1)))

/* Sets retval to power of 2 which is not less than value */
/* TODO: There are better ways to do it ... */
#define	NOT_LESS_POWER_TWO(retval,value,type)\
		{\
			type mask;\
			if((value)==(type)0) {\
				retval=0;\
			} else {\
				mask=(type)1 << ((sizeof(type)<<3)-1);\
				while(!(mask & (value)))\
					mask>>=1;\
				retval = (mask < (value)) ? mask << 1 : mask;\
			}\
		}

/* Sets retval to power of 2 which is greater than value */
/* TODO: There are better ways to do it ... */
#define	GREATER_POWER_TWO(retval,value,type)\
		{\
			type mask;\
			if((value)==(type)0) {\
				retval=1;\
			} else {\
				mask=(type)1 << ((sizeof(type)<<3)-1);\
				while(!(mask & (value)))\
					mask>>=1;\
				retval = (mask <= (value)) ? mask << 1 : mask;\
			}\
		}

#ifndef	SKIP____ARCH_X86 /* WTF ??? I forgot it ... */

/*
 * Byte swaps. Portable and unoptimized.
 * This is cut-and-paste from linux/byteorder/swab.h
 */
#define		SWAP_FOUR_BYTES(x)\
				((u32_t)( \
				(((u32_t)(x) & (u32_t)0x000000ffUL) << 24) | \
				(((u32_t)(x) & (u32_t)0x0000ff00UL) <<  8) | \
				(((u32_t)(x) & (u32_t)0x00ff0000UL) >>  8) | \
				(((u32_t)(x) & (u32_t)0xff000000UL) >> 24) ))

#define 	SWAP_TWO_BYTES(x)\
				((u16_t)( \
				(((u16_t)(x) & (u16_t)0x00ffU) << 8) | \
				(((u16_t)(x) & (u16_t)0xff00U) >> 8) ))

#else	/* ARCH_X86 */

#ifdef	__GCC__

inline static unsigned short SWAP_TWO_BYTES(unsigned short x)
{
  __asm("xchgb %b0,%h0"	:
        "=q" (x)	:
        "0" (x));
    return x;
}

inline static unsigned int SWAP_FOUR_BYTES(unsigned int x)
{
 __asm("bswap	%0":
      "=r" (x)     :
      "0" (x));
  return x;
}

#elif defined(__WATCOM__)

unsigned short SWAP_TWO_BYTES(unsigned short x);
#pragma aux SWAP_TWO_BYTES = \
	"xchg ah,al" \
	parm[ax] result[ax];
	
unsigned long SWAP_FOUR_BYTES(unsigned long x);
#pragma aux SWAP_FOUR_BYTES = \
	"bswap eax" \
	parm[eax] result[eax];

#else	/* !__WATCOM__ */

__inline unsigned short SWAP_TWO_BYTES(unsigned short x)
{
	asm {
		mov ax, x
		xchg ah, al
	}
}

__inline unsigned long SWAP_FOUR_BYTES(unsigned long x)
{
	asm {
		mov eax, x
		bswap eax
	}
}

#endif	/* !__WATCOM__ */

#endif	/* ARCH_X86 */

/*
 * LE2ME: little-endian to machine-endian
 * BE2ME: big-endian to machine-endian
 */

#if			__BYTE_ORDER == __LITTLE_ENDIAN

#ifndef		LE2ME_SHORT
#define		LE2ME_SHORT(sw)		(sw)
#define		ME2LE_SHORT(sw)		(sw)
#endif		/* LITTLE_SHORT */

#ifndef		LE2ME_LONG
#define		LE2ME_LONG(lw)		(lw)
#define		ME2LE_LONG(lw)		(lw)
#endif		/* LITTLE_LONG */

#ifndef		BE2ME_SHORT
#define		BE2ME_SHORT(sw)		SWAP_TWO_BYTES(sw)
#define		ME2BE_SHORT(sw)		SWAP_TWO_BYTES(sw)
#endif		/* LITTLE_SHORT */

#ifndef		BE2ME_LONG
#define		BE2ME_LONG(lw)		SWAP_FOUR_BYTES(lw)
#define		ME2BE_LONG(lw)		SWAP_FOUR_BYTES(lw)
#endif		/* LITTLE_LONG */

#elif		__BYTE_ORDER == __BIG_ENDIAN

#ifndef		LE2ME_SHORT
#define		LE2ME_SHORT(sw)		SWAP_TWO_BYTES(sw)
#define		ME2LE_SHORT(sw)		SWAP_TWO_BYTES(sw)
#endif		/* LITTLE_SHORT */

#ifndef		LE2ME_LONG
#define		LE2ME_LONG(lw)		SWAP_FOUR_BYTES(lw)
#define		ME2LE_LONG(lw)		SWAP_FOUR_BYTES(lw)
#endif		/* LITTLE_LONG */

#ifndef		BE2ME_SHORT
#define		BE2ME_SHORT(sw)		(sw)
#define		ME2BE_SHORT(sw)		(sw)
#endif		/* LITTLE_SHORT */

#ifndef		BE2ME_LONG
#define		BE2ME_LONG(lw)		(lw)
#define		ME2BE_LONG(lw)		(lw)
#endif		/* LITTLE_LONG */

#endif	/* __BYTE_ORDER == __BIG_ENDIAN */

#endif	/* V_TYPES_H */
