//========================================================================================================
// E library
//
// - Basic type definitions and byte-order independence macros
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Aug-07 22:24:59
//
// Copyright (C) 1996-2026 By Gabor Nagy. All rights reserved.
//========================================================================================================
#ifndef _ETypes_h
#define _ETypes_h

#include <stdint.h>  // int32_t etc.

// If not 0, do a public release build. Disable experimental and debugging features, including full freeing at exit.
// Set this to 0 to debug memory leaks on exit!
//
#define ERELEASE_BUILD  1

#define ECount(p)  (sizeof(p) / sizeof(p[0]))

//#include <EConfig.h>

#ifndef typeof
#define typeof __typeof__
#endif

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif


#ifdef sgi
	#ifdef CORE_MAGIC64
		#define EPointer_BITS   64
		#define EIndex_BITS     64
	#else
		#define EPointer_BITS   32
		#define EIndex_BITS     32
	#endif
#else
	#ifdef __x86_64__
		#define EPointer_BITS   64
		#define EIndex_BITS     64
	#else
//		#if TARGET_CPU_ARM64
//		#if TARGET_CPU_X86_64
//		#if TARGET_CPU_ARM64 || TARGET_CPU_X86_64
		#if __APPLE__
			#define EPointer_BITS   64
			#define EIndex_BITS     64
		#else
			#define EPointer_BITS   32
			#define EIndex_BITS     32
		#endif
	#endif
#endif



#ifdef WIN32
	#define WINDOWS
#else
	#ifdef WIN64
		#define WINDOWS
	#endif
#endif


typedef char*           EString;
typedef const char*     EConstString;
typedef const uint8_t*  EConstUInt8P;

typedef uint16_t  EKeyCode;
typedef uint32_t  EKeyModifiers;

#define EClr(pDst)               memset(pDst, 0, sizeof(pDst))
#define EClr_p(pDst)             memset(pDst, 0, sizeof(*(pDst)))
#define EClr_s(pDst)             memset(&(pDst), 0, sizeof(pDst))
#define EClr_a(pDst)             memset(pDst, 0, sizeof(pDst))
#define EClrN(pCount, pDst)      memset(pDst, 0, sizeof((pDst)[0]) * (pCount))
#define ECopy(pSrc, pDst)        memcpy(pDst, pSrc, sizeof(pSrc))
#define ECopy_p(pSrc, pDst)      memcpy(pDst, pSrc, sizeof(*(pSrc)))


#ifdef WINDOWS
	#include <windows.h>
	#include <stdio.h>
	#include <winsock.h>
	#include <string.h>
	#pragma warning (disable:4244)  // Disable bogus conversion warnings

	#define EStat  struct statvfs

#else

	#define EStat  struct stat

	#ifndef UNIX
		#define UNIX
		#include <strings.h>
		#include <sys/types.h>

		#ifdef sgi
			#include <sys/endian.h>
		#endif

		#if defined sgi
			#define EFinite(p)	finite(p)
		#else
			#if defined __APPLE__
				#define EFinite(p)	isfinite(p)
			#else
				#define EFinite(p)	finitef(p)
			#endif	// __APPLE__
		#endif
	#endif // UNIX

	typedef uint64_t	u_long64;
	typedef int64_t		s_long64;

#endif // WIN32


#define ELstEND		-1

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration
#endif


// Edit operators
//
enum
{
	EEditADD = 1,
	EEditDEL,
	EEditMODIFY
};


// Flag (bit) operations
enum
{
	E_SET = 1,  // |= bits
	E_CLEAR,    // &= ~bits
	E_COPY      // = bits
};


//
// Matrix addressing
//
#ifndef M00

// 4x4 Matrix addresses
#define M00	0
enum
{
	   M01=1, M02, M03,
	M10, M11, M12, M13,
	M20, M21, M22, M23,
	M30, M31, M32, M33
};

// 3x3 Matrix addresses
#define M3x00  0
enum
{
		   M3x01=1, M3x02,
	M3x10, M3x11, M3x12,
	M3x20, M3x21, M3x22,
};

#endif	// M00



// This is used for tracking down Heisen-bugs, where adding a printf makes the bug go away
//
typedef struct
{
	const char*  FileName;
	const char*  Function;
	int          Line;
	char*        Message;
	int          SetCount;
} ECodePoint;


#define EMAX_CALLSTACK_DEPTH		32

typedef struct
{
// These members provide source code reference for the first entry in CallStack, even in non-debug builds.
//
	const char*  FileName;
	const char*  Function;
	int          Line;

	void*        CallStack[EMAX_CALLSTACK_DEPTH];int  CallStackDepth;
} ECallerInfo;


// NOP macros
//
#define _EM_NOP1(p0)
#define _EM_NOP2(p0, p1)
#define _EM_NOP3(p0, p1, p2)
#define _EM_NOP4(p0, p1, p2, p3)


#define ECodePoint_Clear(p) do\
{\
	p.FileName = NULL;\
	p.Function = NULL;\
	p.Line = 0;\
	p.SetCount = 0;\
} while(0)


#define ECodePoint_Set(p) do\
{\
	p.FileName = __FILE__;\
	p.Function = __FUNCTION__;\
	p.Line = __LINE__;\
	p.Message = NULL;\
	p.SetCount++;\
} while(0)


#define ECodePoint_SetMsg(p, pMessage) do\
{\
	p.FileName = __FILE__;\
	p.Function = __FUNCTION__;\
	p.Line = __LINE__;\
	p.SetCount++;\
	if(p.Message) EFree(p.Message);p.Message = EStrDup(pMessage);\
} while(0)


//
// 'Desperate' version of ECodePoint_SetMsg, for when even EStrDup makes the bug go away
// Use only as a last-last resort because it simply assigns pMessage (which may be overwritten)...
//
#define ECodePoint_SetMsgD(p, pMessage) do\
{\
	p.FileName = __FILE__;\
	p.Function = __FUNCTION__;\
	p.Line = __LINE__;\
	p.SetCount++;\
	p.Message = pMessage;\
} while(0)



#ifndef EBIG_ENDIAN
	#define EBIG_ENDIAN	0
	#define ELITTLE_ENDIAN	1

	#ifdef BYTE_ORDER
		#if BYTE_ORDER == BIG_ENDIAN
			#define EBYTE_ORDER	EBIG_ENDIAN
		#else
			#define EBYTE_ORDER	ELITTLE_ENDIAN
		#endif
	#endif
#endif



//
// Initializer macros
//
#define ESetN(pDst, pValue, pCount) do\
{\
	EIndex  lI = 0;const EIndex  lN = pCount;for(;lI < lN;lI++)\
	{\
		pDst[lI] = pValue;\
	}\
} while(0)


#define E_SetXY_s(s, pX, pY)            do { (s).X = pX, (s).Y = pY; } while(0)

#define E_Set3_a(s,  p0, p1, p2)        do { (s)[0] = p0, (s)[1] = p1, (s)[2] = p2; } while(0)
#define E_SetXYZ_s(s, pX, pY, pZ)       do { (s).X = pX, (s).Y = pY, (s).Z = pZ; } while(0)
#define E_SetXYZ_p(s, pX, pY, pZ)       do { (s)->X = pX, (s)->Y = pY, (s)->Z = pZ; } while(0)

#define E_CopyXYZ_s(s, d)               do { (d).X = (s).X, (d).Y = (s).Y, (d).Z = (s).Z; } while(0)

#define E_SetRGB_s(s, pR, pG, pB)       do { (s).R = pR,  (s).G = pG,  (s).B = pB; } while(0)
#define E_MultRGB_s(p, pS)              do { (p).R *= pS,  (p).G *= pS,  (p).B *= pS; } while(0)
#define E_SetRGB_p(s, pR, pG, pB)       do { (s)->R = pR, (s)->G = pG, (s)->B = pB; } while(0)

#define E_Set4_a(s,  p0, p1, p2, p3)    do { (s)[0] = p0, (s)[1] = p1, (s)[2] = p2, (s)[3] = p3; } while(0)
#define E_SetRGBA_s(s, pR, pG, pB, pA)  do { (s).R = pR,  (s).G = pG,  (s).B = pB,  (s).A = pA; } while(0)
#define E_SetRGBA_p(s, pR, pG, pB, pA)  do { (s)->R = pR, (s)->G = pG, (s)->B = pB, (s)->A = pA; } while(0)

#define E_Lerp(p0, p1, pT, pOut) do\
{\
	const float  lTInv = 1.0 - pT;\
	pOut = p0 * lTInv + p1 * pT;\
}\
while(0)

//
// Struct element references, e.g. for printf
//
#define RGB_s(pV)     (pV).R,  (pV).G,  (pV).B
#define RGB_p(pV)     (pV)->R, (pV)->G, (pV)->B
#define RGB_a(pV)     (pV)[0],  (pV)[1],  (pV)[2]
#define RGBA_s(pV)    (pV).R,  (pV).G,  (pV).B,  (pV).A
#define RGBA_sll(pV)  (long long)(pV).R,  (long long)(pV).G,  (long long)(pV).B,  (long long)(pV).A

#define RGBA_p(pV)    (pV)->R, (pV)->G, (pV)->B, (pV)->A
#define RGBA_a(pV)    (pV)[0], (pV)[1], (pV)[2], (pV)[3]
#define RGBA_c(pV)    pV##R, pV##G, pV##B, pV##A
#define RGBA_cll(pV)  (long long)(pV##R), (long long)(pV##G), (long long)(pV##B), (long long)(pV##A)

#define XY_c(pV)    pV##X,  pV##Y
#define XY_cll(pV)  (long long)(pV##X), (long long)(pV##Y)
#define XY_a(pV)    (pV)[0],  (pV)[1]
#define XY_s(pV)    (pV).X,   (pV).Y
#define XY_sll(pV)  (long long)(pV).X, (long long)(pV).Y
#define XY_p(pV)    (pV)->X,  (pV)->Y
#define XY_pll(pV)  (long long)(pV)->X, (long long)(pV)->Y

#define XYZ_c(pV)   pV##X,  pV##Y,  pV##Z
#define XYZ_cll(pV)  (long long)(pV##X), (long long)(pV##Y), (long long)(pV##Z)
#define XYZ_sll(pV)  (long long)(pV).X, (long long)(pV).Y, (long long)(pV).Z
#define XYZ_a(pV)  (pV)[0],  (pV)[1],  (pV)[2]
#define XYZ_all(pV)  (long long)(pV)[0],  (long long)(pV)[1],  (long long)(pV)[2]
#define XYZ_s(pV)  (pV).X,   (pV).Y,   (pV).Z
#define XYZ_p(pV)  (pV)->X,  (pV)->Y,  (pV)->Z

#define XYZW_a(pV)  (pV)[0],  (pV)[1],  (pV)[2],  (pV)[3]
#define XYZW_s(pV)  (pV).X,   (pV).Y,   (pV).Z,   (pV).W
#define XYZW_p(pV)  (pV)->X,  (pV)->Y,  (pV)->Z,  (pV)->W

#define E_Swap(pA, pB) do\
{\
	const typeof(pA)  lTmp = pA;\
	pA = pB;pB = lTmp;\
} while(0)

#define E_Swap_f  E_Swap

// CPU byte order-independence macros
//
#if defined(EM_GetInt16)
#else

#define EM_PutStringI(pStr, pPtr) do\
{\
	const int  lLen = strlen(pStr);\
\
	strcpy((char*)pPtr, pStr);\
	pPtr += (lLen + 1);\
	pPtr[lLen] = 0;\
} while(0)


#define EM_SwapBytes4(v) do\
{\
	uint8_t*	pPtr = (uint8_t*)((v));\
	uint8_t	lV;\
\
	lV = pPtr[0];pPtr[0] = pPtr[3];pPtr[3] = lV;\
	lV = pPtr[1];pPtr[1] = pPtr[2];pPtr[2] = lV;\
} while(0)



#define EM_GetInt16_be(v, buffer)   do { v = (int16_t)(((((uint16_t)(((uint8_t*)(buffer))[0])) << 8) | ((uint16_t)(((uint8_t*)(buffer))[1])))); } while(0)
#define EM_GetInt16I_be(v, buffer)  do { v = (int16_t)(((((uint16_t)((buffer)[0]))) << 8) | ((uint16_t)((buffer)[1]))), buffer += 2; } while(0)

#define EM_PutInt16_be(v, buffer)	   do { (buffer)[0] = ((v)>>8), (buffer)[1] = ((v) & 0xFF); } while(0)
#define EM_PutInt16I_be(v, buffer)	 do { (buffer)[0] = ((v)>>8), (buffer)[1] = ((v) & 0xFF), (buffer) += 2; } while(0)

#define EM_GetUInt16_be(v, buffer)   do { v = ((((uint16_t)(((uint8_t*)(buffer))[0])) << 8) | ((uint16_t)(((uint8_t*)(buffer))[1]))); } while(0)
#define EM_GetUInt16I_be(v, buffer)  do { v = ((((uint16_t)((buffer)[0]))) << 8) | ((uint16_t)((buffer)[1])), buffer += 2; } while(0)

#define EM_GetUInt16_le(v, buffer)   do { v = ((((uint16_t)((buffer)[1]))) << 8) | ((uint16_t)((buffer)[0])); } while(0)
#define EM_GetUInt16I_le(v, buffer)  do { v = ((((uint16_t)((buffer)[1]))) << 8) | ((uint16_t)((buffer)[0])), buffer += 2; } while(0)

#define E_GetUInt16_be(buffer)   ((((uint16_t)(((uint8_t*)(buffer))[0])) << 8) | ((uint16_t)(((uint8_t*)(buffer))[1])))
#define E_GetUInt16_le(buffer)   ((((uint16_t)(((uint8_t*)(buffer))[1])) << 8) | ((uint16_t)(((uint8_t*)(buffer))[0])))

#define EM_PutUInt16_be(v, buffer)   do { (buffer)[0] = ((v)>>8), (buffer)[1] = ((v) & 0xFF); } while(0)
#define EM_PutUInt16I_be(v, buffer)  do { (buffer)[0] = ((v)>>8), (buffer)[1] = ((v) & 0xFF), (buffer) += 2; } while(0)


#define EM_GetInt32_be(v, buffer) do\
{\
	const uint8_t*  lBuffer = (uint8_t*)buffer;\
	v = (int32_t)(((((uint32_t)(lBuffer)[0])) << 24) | ((((uint32_t)(lBuffer)[1])) << 16) | ((((uint32_t)(lBuffer)[2])) << 8) | ((uint32_t)(lBuffer)[3]));\
} while(0)

#define EM_GetInt32I_be(v, buffer) do\
{\
	v = (int32_t)(((((uint32_t)(buffer)[0])) << 24) | ((((uint32_t)(buffer)[1])) << 16) | ((((uint32_t)(buffer)[2])) << 8) | ((uint32_t)(buffer)[3])), buffer += 4;\
} while(0)

#define EM_GetInt32I_le(v, buffer) do\
{\
	v = ((((int32_t)(buffer)[3])) << 24) | ((((int32_t)(buffer)[2])) << 16) | ((((int32_t)(buffer)[1])) << 8) | ((int32_t)(buffer)[0]), buffer += 4;\
} while(0)

#define EM_GetInt64I_be(v, buffer) do\
{\
	const uint8_t*  lP = buffer;\
	v = (int64_t)((((uint64_t)(lP[0])) << 56) | (((uint64_t)(lP[1])) << 48) | (((uint64_t)(lP[2])) << 40) | (((uint64_t)(lP[3])) << 32) |\
	(((uint64_t)(lP[4])) << 24) | (((uint64_t)(lP[5])) << 16) | (((uint64_t)(lP[6])) << 8) | (uint64_t)(lP[7]));\
	buffer += 8;\
} while(0)

#define EM_GetUInt64I_be(v, buffer)	do\
{\
	const uint8_t*  lP = buffer;v = (((uint64_t)(lP[0])) << 56) | (((uint64_t)(lP[1])) << 48) | (((uint64_t)(lP[2])) << 40) | (((uint64_t)(lP[3])) << 32) |\
	(((uint64_t)(lP[4])) << 24) | (((uint64_t)(lP[5])) << 16) | (((uint64_t)(lP[6])) << 8) | (uint64_t)(lP[7]);\
	buffer += 8;\
} while(0)

#define EM_GetUInt32_be(v, buffer) do\
{\
	v = ((((uint32_t)(buffer)[0])) << 24) | ((((uint32_t)(buffer)[1])) << 16) | ((((uint32_t)(buffer)[2])) << 8) | ((uint32_t)(buffer)[3]);\
} while(0)

#define EM_GetUInt32_le(v, buffer) do\
{\
	v = ((((uint32_t)(buffer)[3])) << 24) | ((((uint32_t)(buffer)[2])) << 16) | ((((uint32_t)(buffer)[1])) << 8) | ((uint32_t)(buffer)[0]);\
} while(0)

#define EM_GetUInt32I_be(v, buffer) do\
{\
	v = ((((uint32_t)(buffer)[0])) << 24) | ((((uint32_t)(buffer)[1])) << 16) | ((((uint32_t)(buffer)[2])) << 8) | ((uint32_t)(buffer)[3]), buffer += 4;\
} while(0)

#define EM_GetUInt32I_le(v, buffer) do\
{\
	v = ((((uint32_t)(buffer)[3])) << 24) | ((((uint32_t)(buffer)[2])) << 16) | ((((uint32_t)(buffer)[1])) << 8) | ((uint32_t)(buffer)[0]), buffer += 4;\
} while(0)

#define EM_GetUInt64I_le(v, buffer) do\
{\
	v = ((((uint64_t)(buffer)[7])) << 56) | ((((uint64_t)(buffer)[6])) << 48) | ((((uint64_t)(buffer)[5])) << 40) | ((((uint64_t)(buffer)[4])) << 32) |\
	((((uint64_t)(buffer)[3])) << 24) | ((((uint64_t)(buffer)[2])) << 16) | ((((uint64_t)(buffer)[1])) << 8) | ((uint64_t)(buffer)[0]);\
	buffer += 8;\
} while(0)


#define EM_PutInt64I_be(v, buffer) do\
{\
	const int64_t	 lI = v;\
	(buffer)[0] = lI >> 56, (buffer)[1] = lI >> 48, (buffer)[2] = lI >> 40, (buffer)[3] = lI >> 32;\
	(buffer)[4] = lI >> 24, (buffer)[5] = lI >> 16, (buffer)[6] = lI >>  8, (buffer)[7] = lI;\
	(buffer) += 8;\
} while(0)

#define EM_PutUInt64_be(v, buffer) do\
{\
	uint8_t*        lBuffer = (uint8_t*)(buffer);\
	const uint64_t	lI = v;\
	lBuffer[0] = lI >> 56, lBuffer[1] = lI >> 48, lBuffer[2] = lI >> 40, lBuffer[3] = lI >> 32;\
	lBuffer[4] = lI >> 24, lBuffer[5] = lI >> 16, lBuffer[6] = lI >>  8, lBuffer[7] = lI;\
} while(0)

#define EM_PutUInt64I_be(v, buffer) do\
{\
	const uint64_t	lI = v;\
	(buffer)[0] = lI >> 56, (buffer)[1] = lI >> 48, (buffer)[2] = lI >> 40, (buffer)[3] = lI >> 32;\
	(buffer)[4] = lI >> 24, (buffer)[5] = lI >> 16, (buffer)[6] = lI >>  8, (buffer)[7] = lI;\
	(buffer) += 8;\
} while(0)

#define EM_PutInt32_be(v, buffer) do\
{\
	const int32_t	lI = v;\
	(buffer)[0] = lI >> 24, (buffer)[1] = lI >> 16, (buffer)[2] = lI >> 8, (buffer)[3] = lI;\
} while(0)

#define EM_PutInt32I_be(v, buffer) do\
{\
	const int32_t	lI = v;\
	(buffer)[0] = lI >> 24, (buffer)[1] = lI >> 16, (buffer)[2] = lI >> 8, (buffer)[3] = lI;\
	(buffer) += 4;\
} while(0)

#define EM_PutUInt32_be(v, buffer) do\
{\
	const uint32_t	lI = v;\
	(buffer)[0] = lI >> 24, (buffer)[1] = lI >> 16, (buffer)[2] = lI >> 8, (buffer)[3] = lI;\
} while(0)

#define EM_PutUInt32I_be(v, buffer) do\
{\
	const uint32_t	lI = v;\
	(buffer)[0] = lI >> 24, (buffer)[1] = lI >> 16, (buffer)[2] = lI >> 8, (buffer)[3] = lI;\
	(buffer) += 4;\
} while(0)



// Memory I/O
// Even with matching endianness, the source / destination pointer might not be properly aligned, so the native versions still do a byte copy
//
#define EM_GetFloat16_native(v, buffer) do\
{\
	_MFloat16Ptr[0] = ((uint8_t*)(buffer))[0], _MFloat16Ptr[1] = ((uint8_t*)(buffer))[1],\
	v = _MFloat32;\
} while(0)

#define EM_GetFloat16_swapped(v, buffer) do\
{\
	_MFloat16Ptr[0] = ((uint8_t*)(buffer))[1], _MFloat16Ptr[1] = ((uint8_t*)(buffer))[0],\
	v=_MFloat32\
} while(0)


#define EM_GetFloat16I_native(v, buffer) do\
{\
	_MFloat16Ptr[0] = ((uint8_t*)(buffer))[0], _MFloat16Ptr[1] = ((uint8_t*)(buffer))[1],\
	v = _MFloat32, (buffer) += 2;\
} while(0)

#define EM_GetFloat16I_swapped(v, buffer) do\
{\
	_MFloat16Ptr[0] = ((uint8_t*)(buffer))[1], _MFloat16Ptr[1] = ((uint8_t*)(buffer))[0],\
	v = _MFloat32, (buffer) += 2;\
} while(0)


#define EM_GetFloat32_native(v, buffer) do\
{\
	_MFloat32Ptr[0] = ((uint8_t*)(buffer))[0], _MFloat32Ptr[1] = ((uint8_t*)(buffer))[1], _MFloat32Ptr[2] = ((uint8_t*)(buffer))[2], _MFloat32Ptr[3] = ((uint8_t*)(buffer))[3],\
	v = _MFloat32;\
} while(0)

#define EM_GetFloat32_swapped(v, buffer) do\
{\
	_MFloat32Ptr[0] = ((uint8_t*)(buffer))[3], _MFloat32Ptr[1] = ((uint8_t*)(buffer))[2], _MFloat32Ptr[2] = ((uint8_t*)(buffer))[1], _MFloat32Ptr[3] = ((uint8_t*)(buffer))[0],\
	v = _MFloat32;\
} while(0)


#define EM_GetFloat32I_swapped(v, buffer) do\
{\
	_MFloat32Ptr[0] = ((uint8_t*)(buffer))[3], _MFloat32Ptr[1] = ((uint8_t*)(buffer))[2], _MFloat32Ptr[2] = ((uint8_t*)(buffer))[1], _MFloat32Ptr[3] = ((uint8_t*)(buffer))[0],\
	v = _MFloat32, (buffer) += 4;\
} while(0)

#define EM_GetFloat32I_native(v, buffer) do\
{\
	_MFloat32Ptr[0] = ((uint8_t*)(buffer))[0], _MFloat32Ptr[1] = ((uint8_t*)(buffer))[1], _MFloat32Ptr[2] = ((uint8_t*)(buffer))[2], _MFloat32Ptr[3] = ((uint8_t*)(buffer))[3],\
	v = _MFloat32, (buffer) += 4;\
} while(0)


#define EM_GetFloat64_native(v, buffer) do\
{\
  _MFloat64Ptr[0] = ((uint8_t*)(buffer))[0],\
	_MFloat64Ptr[1] = ((uint8_t*)(buffer))[1],\
	_MFloat64Ptr[2] = ((uint8_t*)(buffer))[2],\
	_MFloat64Ptr[3] = ((uint8_t*)(buffer))[3],\
	_MFloat64Ptr[4] = ((uint8_t*)(buffer))[4],\
	_MFloat64Ptr[5] = ((uint8_t*)(buffer))[5],\
	_MFloat64Ptr[6] = ((uint8_t*)(buffer))[6],\
	_MFloat64Ptr[7] = ((uint8_t*)(buffer))[7],\
	v = _MFloat64;\
} while(0)

#define EM_GetFloat64_swapped(v, buffer) do\
{\
	_MFloat64Ptr[0] = ((uint8_t*)(buffer))[7],\
	_MFloat64Ptr[1] = ((uint8_t*)(buffer))[6],\
	_MFloat64Ptr[2] = ((uint8_t*)(buffer))[5],\
	_MFloat64Ptr[3] = ((uint8_t*)(buffer))[4],\
	_MFloat64Ptr[4] = ((uint8_t*)(buffer))[3],\
	_MFloat64Ptr[5] = ((uint8_t*)(buffer))[2],\
	_MFloat64Ptr[6] = ((uint8_t*)(buffer))[1],\
	_MFloat64Ptr[7] = ((uint8_t*)(buffer))[0],\
	v = _MFloat64;\
} while(0)


#define EM_GetFloat64I_native(v, buffer) do\
{\
	_MFloat64Ptr[0] = ((uint8_t*)(buffer))[0],\
	_MFloat64Ptr[1] = ((uint8_t*)(buffer))[1],\
	_MFloat64Ptr[2] = ((uint8_t*)(buffer))[2],\
	_MFloat64Ptr[3] = ((uint8_t*)(buffer))[3],\
	_MFloat64Ptr[4] = ((uint8_t*)(buffer))[4],\
	_MFloat64Ptr[5] = ((uint8_t*)(buffer))[5],\
	_MFloat64Ptr[6] = ((uint8_t*)(buffer))[6],\
	_MFloat64Ptr[7] = ((uint8_t*)(buffer))[7],\
	v=_MFloat64, (buffer) += 8;\
} while(0)

#define EM_GetFloat64I_swapped(v, buffer) do\
{\
	_MFloat64Ptr[0] = ((uint8_t*)(buffer))[7],\
	_MFloat64Ptr[1] = ((uint8_t*)(buffer))[6],\
	_MFloat64Ptr[2] = ((uint8_t*)(buffer))[5],\
	_MFloat64Ptr[3] = ((uint8_t*)(buffer))[4],\
	_MFloat64Ptr[4] = ((uint8_t*)(buffer))[3],\
	_MFloat64Ptr[5] = ((uint8_t*)(buffer))[2],\
	_MFloat64Ptr[6] = ((uint8_t*)(buffer))[1],\
	_MFloat64Ptr[7] = ((uint8_t*)(buffer))[0],\
	v = _MFloat64, (buffer) += 8;\
} while(0)



#define EM_PutFloat16_native(v, buffer)	do { _MFloat16 = v, buffer[0] = _MFloat16Ptr[0], buffer[1] = _MFloat16Ptr[1]; } while(0)

#define EM_PutFloat16_swapped(v, buffer) do\
{\
 _MFloat16 = v,buffer[0] = _MFloat16Ptr[1],buffer[1] = _MFloat16Ptr[0];\
} while(0)


#define EM_PutFloat16I_native(v, buffer)	do { _MFloat16 = v, buffer[0] = _MFloat16Ptr[0], buffer[1] = _MFloat16Ptr[1], (buffer) += 2; } while(0)

#define EM_PutFloat16I_swapped(v, buffer) do\
{\
 _MFloat16 = v,buffer[0] = _MFloat16Ptr[1],buffer[1] = _MFloat16Ptr[0], (buffer) += 2;\
} while(0)


#define EM_PutFloat32_native(v, buffer)	do\
{\
	_MFloat32 = v, buffer[0] = _MFloat32Ptr[0], buffer[1] = _MFloat32Ptr[1], buffer[2] = _MFloat32Ptr[2], buffer[3] = _MFloat32Ptr[3];\
} while(0)

#define EM_PutFloat32_swapped(v, buffer) do\
{\
	_MFloat32 = v,buffer[3] = _MFloat32Ptr[0];buffer[2] = _MFloat32Ptr[1];buffer[1] = _MFloat32Ptr[2];buffer[0] = _MFloat32Ptr[3];\
} while(0)


#define EM_PutFloat32I_native(v, buffer) do\
{\
	_MFloat32 = v, buffer[0] = _MFloat32Ptr[0], buffer[1] = _MFloat32Ptr[1], buffer[2] = _MFloat32Ptr[2], buffer[3] = _MFloat32Ptr[3], (buffer) += 4;\
} while(0)

#define EM_PutFloat32I_swapped(v, buffer) do\
{\
	_MFloat32 = v;buffer[3] = _MFloat32Ptr[0];buffer[2] = _MFloat32Ptr[1];buffer[1] = _MFloat32Ptr[2];buffer[0] = _MFloat32Ptr[3];(buffer) += 4;\
} while(0)


#define EM_PutFloat64_native(v, buffer) do\
{\
	_MFloat64 = v,\
	buffer[0] = _MFloat64Ptr[0],\
	buffer[1] = _MFloat64Ptr[1],\
	buffer[2] = _MFloat64Ptr[2],\
	buffer[3] = _MFloat64Ptr[3],\
	buffer[4] = _MFloat64Ptr[4],\
	buffer[5] = _MFloat64Ptr[5],\
	buffer[6] = _MFloat64Ptr[6],\
	buffer[7] = _MFloat64Ptr[7];\
} while(0)

#define EM_PutFloat64_swapped(v, buffer) do\
{\
	_MFloat64 = v,\
	buffer[0]=_MFloat64Ptr[7],\
	buffer[1]=_MFloat64Ptr[6],\
	buffer[2]=_MFloat64Ptr[5],\
	buffer[3]=_MFloat64Ptr[4],\
	buffer[4]=_MFloat64Ptr[3],\
	buffer[5]=_MFloat64Ptr[2],\
	buffer[6]=_MFloat64Ptr[1],\
	buffer[7]=_MFloat64Ptr[0];\
} while(0)


#define EM_PutFloat64I_native(v, buffer) do\
{\
	_MFloat64 = v,\
	buffer[0] = _MFloat64Ptr[0],\
	buffer[1] = _MFloat64Ptr[1],\
	buffer[2] = _MFloat64Ptr[2],\
	buffer[3] = _MFloat64Ptr[3],\
	buffer[4] = _MFloat64Ptr[4],\
	buffer[5] = _MFloat64Ptr[5],\
	buffer[6] = _MFloat64Ptr[6],\
	buffer[7] = _MFloat64Ptr[7];\
	(buffer) += 8;\
} while(0)

#define EM_PutFloat64I_swapped(v, buffer) do\
{\
	_MFloat64 = v,\
	buffer[0] = _MFloat64Ptr[7],\
	buffer[1] = _MFloat64Ptr[6],\
	buffer[2] = _MFloat64Ptr[5],\
	buffer[3] = _MFloat64Ptr[4],\
	buffer[4] = _MFloat64Ptr[3],\
	buffer[5] = _MFloat64Ptr[2],\
	buffer[6] = _MFloat64Ptr[1],\
	buffer[7] = _MFloat64Ptr[0], (buffer) += 8;\
} while(0)


// File I/O
//
// Temporary variables for CPU byte order-independence macros
//

/*
extern EFloat16  _MFloat16;
extern float     _MFloat32;
extern double    _MFloat64;
extern uint8_t*  _MFloat16Ptr;
extern uint8_t*  _MFloat32Ptr;
extern uint8_t*  _MFloat64Ptr;
*/



#define EM_freadInt16_native(pPtr, pFile)  E_fread(&pPtr, 2, 1, pFile)

#define EM_freadInt16_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[2];\
	E_fread(lSwapBuffer, 2, 1, pFile);\
	v = (((uint16_t)(lSwapBuffer[0])) << 8) | ((uint16_t)(lSwapBuffer[1]));\
} while(0)

#define EM_freadInt16_r_swapped(v, pFile, pRet) do\
{\
	uint8_t  lSwapBuffer[2];\
	pRet = fread(lSwapBuffer, 2, 1, pFile);\
	v = (((uint16_t)(lSwapBuffer[0])) << 8) | ((uint16_t)(lSwapBuffer[1]));\
} while(0)

#define EM_freadInt16_r_native(pPtr, pFile, pRet)  pRet = fread(&pPtr, 2, 1, pFile)


#define EM_freadInt16P_native(pPtr, pFile)  E_fread(pPtr, 2, 1, pFile)

#define EM_freadInt16P_swapped(pPtr, pFile) do\
{\
	uint8_t  lSwapBuffer[2];\
	E_fread(lSwapBuffer, 2, 1, pFile);\
	*(pPtr) = (((uint16_t)(lSwapBuffer[0]))<<8) | ((uint16_t)(lSwapBuffer[1]));\
} while(0)


#define EM_freadInt32_native(pPtr, pFile)  E_fread(&pPtr, 4, 1, pFile)

#define EM_freadInt32_swapped(pPtr, pFile) do\
{\
	uint8_t  lSwapBuffer[4];\
	E_fread(lSwapBuffer, 4, 1, pFile);\
	pPtr = (int32_t)((((uint32_t)(lSwapBuffer[0]))<<24) | (((uint32_t)(lSwapBuffer[1]))<<16) | (((uint32_t)(lSwapBuffer[2]))<<8) | ((uint32_t)(lSwapBuffer[3])));\
} while(0)


#define EM_freadUInt32_swapped(pPtr, pFile) do\
{\
	uint8_t  lSwapBuffer[4];\
	E_fread(lSwapBuffer, 4, 1, pFile);\
	pPtr = ((((uint32_t)(lSwapBuffer[0]))<<24) | (((uint32_t)(lSwapBuffer[1]))<<16) | (((uint32_t)(lSwapBuffer[2]))<<8) | ((uint32_t)(lSwapBuffer[3])));\
} while(0)


#define EM_freadInt64_native(pPtr, pFile)  E_fread(&pPtr, 8, 1, pFile)

#define EM_freadInt64_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[8];\
	E_fread(lSwapBuffer, 8, 1, pFile);\
	v = (int64_t)((((uint64_t)(lSwapBuffer[0]))<<56) | (((uint64_t)(lSwapBuffer[1]))<<48) | (((uint64_t)(lSwapBuffer[2]))<<40) | ((uint64_t)((lSwapBuffer[3]))<<32) |\
	    ((((uint64_t)(lSwapBuffer[4]))<<24) | (((uint64_t)(lSwapBuffer[5]))<<16) | (((uint64_t)(lSwapBuffer[6]))<< 8) | ((uint64_t)(lSwapBuffer[7]))));\
} while(0)


#define EM_freadFloat16_native(pPtr, pFile)  E_fread(&pPtr, 2, 1, pFile)

#define EM_freadFloat16_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[2];\
	E_fread(lSwapBuffer, 2, 1, pFile),\
	*(pPtr) = (((EFloat16)(lSwapBuffer[0]))<<8) | ((EFloat16)(lSwapBuffer[1]));\
} while(0)


#define EM_freadFloat32_native(pPtr, pFile)	E_fread(&pPtr, 4, 1, pFile)

#define EM_freadFloat32_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[4];\
	E_fread(lSwapBuffer, 4, 1, pFile);\
	_MFloat32Ptr[0] = lSwapBuffer[3], _MFloat32Ptr[1] = lSwapBuffer[2],_MFloat32Ptr[2] = lSwapBuffer[1],_MFloat32Ptr[3] = lSwapBuffer[0],\
	v = _MFloat32;\
} while(0)


#define EM_freadFloat64_native(pPtr, pFile)	E_fread(&pPtr, 8, 1, pFile)

#define EM_freadFloat64_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[8];\
	E_fread(lSwapBuffer, 8, 1, pFile);\
	_MFloat64Ptr[0] = lSwapBuffer[7], _MFloat64Ptr[1] = lSwapBuffer[6], _MFloat64Ptr[2] = lSwapBuffer[5], _MFloat64Ptr[3] = lSwapBuffer[4],\
	_MFloat64Ptr[4] = lSwapBuffer[3], _MFloat64Ptr[5] = lSwapBuffer[2], _MFloat64Ptr[6] = lSwapBuffer[1], _MFloat64Ptr[7] = lSwapBuffer[0],\
	v = _MFloat64;\
} while(0)


// Write to pFile
//
#define EM_fwriteInt16_native(v, pFile)   do { int16_t   lV = v;fwrite(&lV, 2, 1, pFile); } while(0)

#define EM_fwriteInt16_swapped(v, pFile) do\
{\
	const int16_t  lV = v;\
	uint8_t        lSwapBuffer[2];\
	lSwapBuffer[0] = (uint8_t)(lV >> 8), lSwapBuffer[1] = (uint8_t)lV;\
	E_fwrite(lSwapBuffer, 2, 1, pFile);\
} while(0)


#define EM_fwriteUInt16_native(v, pFile)  do { uint16_t  lV = v;fwrite(&lV, 2, 1, pFile); } while(0)

#define EM_fwriteUInt16_swapped(v, pFile) do\
{\
	const uint16_t  lV = v;\
	uint8_t         lSwapBuffer[2];\
	lSwapBuffer[0] = (uint8_t)(lV >> 8), lSwapBuffer[1] = (uint8_t)lV;\
	E_fwrite(lSwapBuffer, 2, 1, pFile);\
} while(0)


#define EM_writeInt16_native(v, fd)		write(fd, &v, 2)

#define EM_writeInt16_swapped(v, fd) do\
{\
	const uint16_t  lV = v;\
	uint8_t   lSwapBuffer[2];\
	lSwapBuffer[0] = (uint8_t)(lV>>8), lSwapBuffer[1] = (uint8_t)lV;\
	E_write(fd, lSwapBuffer, 2);\
} while(0)


#define EM_fwriteInt32_native(v, pFile)   do { int32_t  lV = v;fwrite(&lV, 4, 1, pFile); } while(0)

#define EM_fwriteInt32_swapped(pPtr, pFile) do\
{\
	const int  lV = pPtr;\
	uint8_t    lSwapBuffer[4];\
	lSwapBuffer[0] = (uint8_t)(lV>>24), lSwapBuffer[1] = (uint8_t)(lV>>16), lSwapBuffer[2] = (uint8_t)(lV>>8), lSwapBuffer[3] = (uint8_t)lV;\
	E_fwrite(lSwapBuffer, 4, 1, pFile);\
} while(0)


#define EM_writeInt32_native(v, fd)		write(fd, &v, 4)

#define EM_writeInt32_swapped(pPtr, fd) do\
{\
	const int  lV = pPtr;\
	uint8_t    lSwapBuffer[4];\
	lSwapBuffer[0] = (uint8_t)(lV>>24), lSwapBuffer[1] = (uint8_t)(lV>>16), lSwapBuffer[2] = (uint8_t)(lV>>8), lSwapBuffer[3] = (uint8_t)lV;\
	E_write(fd, lSwapBuffer, 4);\
} while(0)


#define EM_fwriteUInt32_native(v, pFile)  do { uint32_t  lV = v;fwrite(&lV, 4, 1, pFile); } while(0)

#define EM_fwriteUInt32_swapped(pPtr, pFile) do\
{\
	const uint32_t  lV = pPtr;\
	uint8_t         lSwapBuffer[4];\
	lSwapBuffer[0] = (uint8_t)(lV>>24), lSwapBuffer[1] = (uint8_t)(lV>>16), lSwapBuffer[2] = (uint8_t)(lV>>8), lSwapBuffer[3] = (uint8_t)lV;\
	E_fwrite(lSwapBuffer, 4, 1, pFile);\
} while(0)


#define EM_fwriteInt64_native(v, pFile)   do { int64_t   lV = v;fwrite(&lV, 8, 1, pFile); } while(0)

#define EM_fwriteInt64_swapped(pPtr, pFile) do\
{\
	const int64_t   lV = pPtr;\
	uint8_t         lSwapBuffer[8];\
	lSwapBuffer[0] = (uint8_t)(lV>>56), lSwapBuffer[1] = (uint8_t)(lV>>48), lSwapBuffer[2] = (uint8_t)(lV>>40), lSwapBuffer[3] = (uint8_t)(lV>>32),\
	lSwapBuffer[4] = (uint8_t)(lV>>24), lSwapBuffer[5] = (uint8_t)(lV>>16), lSwapBuffer[6] = (uint8_t)(lV>>8),  lSwapBuffer[7] = (uint8_t)lV;\
	E_fwrite(lSwapBuffer, 8, 1, pFile);\
} while(0)


#define EM_writeInt64_native(v, fd)		write(fd, &v, 8)

#define EM_writeInt64_swapped(pPtr, fd) do\
{\
	const int64_t   lV = pPtr;\
	uint8_t         lSwapBuffer[8];\
	lSwapBuffer[0] = (uint8_t)(lV>>56), lSwapBuffer[1] = (uint8_t)(lV>>48), lSwapBuffer[2] = (uint8_t)(lV>>40), lSwapBuffer[3] = (uint8_t)(lV>>32),\
	lSwapBuffer[4] = (uint8_t)(lV>>24), lSwapBuffer[5] = (uint8_t)(lV>>16), lSwapBuffer[6] = (uint8_t)(lV>>8),  lSwapBuffer[7] = (uint8_t)lV;\
	E_write(fd, lSwapBuffer, 8);\
} while(0)


#define EM_fwriteUInt64_native(v, pFile)  do { uint64_t  lV = v;fwrite(&lV, 8, 1, pFile); } while(0)


#define EM_fwriteFloat16_native(v, pFile)	do { uint16_t  lV = v;fwrite(&lV, 2, 1, pFile); } while(0)


#define EM_fwriteFloat32_native(v, pFile)	do { float     lV = v;fwrite(&lV, 4, 1, pFile); } while(0)

#define EM_fwriteFloat32_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[4];\
	_MFloat32 = v;\
	lSwapBuffer[3] = _MFloat32Ptr[0], lSwapBuffer[2] = _MFloat32Ptr[1], lSwapBuffer[1] = _MFloat32Ptr[2], lSwapBuffer[0] = _MFloat32Ptr[3];\
	E_fwrite(lSwapBuffer, 4, 1, pFile);\
} while(0)


#define EM_fwriteFloat64_native(v, pFile)	do { double    lV = v;fwrite(&lV, 8, 1, pFile); } while(0)

#define EM_fwriteFloat64_swapped(v, pFile) do\
{\
	uint8_t  lSwapBuffer[8];\
	_MFloat64 = v;\
	lSwapBuffer[7] = _MFloat64Ptr[0], lSwapBuffer[6] = _MFloat64Ptr[1], lSwapBuffer[5] = _MFloat64Ptr[2], lSwapBuffer[4] = _MFloat64Ptr[3],\
	lSwapBuffer[3] = _MFloat64Ptr[4], lSwapBuffer[2] = _MFloat64Ptr[5], lSwapBuffer[1] = _MFloat64Ptr[6], lSwapBuffer[0] = _MFloat64Ptr[7];\
	E_fwrite(lSwapBuffer, 8, 1, pFile);\
} while(0)





#if EBYTE_ORDER == EBIG_ENDIAN


// Memory IO
// Even though we're in big endian here, the source / destination pointer might not be properly aligned,
// so we still have to do a byte copy
//
#define EM_GetFloat16_be  EM_GetFloat16_native
#define EM_GetFloat16_le  EM_GetFloat16_swapped

#define EM_GetFloat16I_be  EM_GetFloat16I_native
#define EM_GetFloat16I_le  EM_GetFloat16I_swapped

#define EM_GetFloat32_be  EM_GetFloat32_native
#define EM_GetFloat32_le  EM_GetFloat32_swapped

#define EM_GetFloat32I_be  EM_GetFloat32I_native
#define EM_GetFloat32I_le  EM_GetFloat32I_swapped

#define EM_GetFloat64_be  EM_GetFloat64_native
#define EM_GetFloat64_le  EM_GetFloat64_swapped

#define EM_GetFloat64I_be  EM_GetFloat64I_native
#define EM_GetFloat64I_le  EM_GetFloat64I_swapped

#define EM_PutFloat16_be   EM_PutFloat16_native
#define EM_PutFloat16_le   EM_PutFloat16_swapped

#define EM_PutFloat16I_be  EM_PutFloat16I_native
#define EM_PutFloat16I_le  EM_PutFloat16I_swapped

#define EM_PutFloat32_be   EM_PutFloat32_native
#define EM_PutFloat32_le   EM_PutFloat32_swapped

#define EM_PutFloat32I_be  EM_PutFloat32I_native
#define EM_PutFloat32I_le  EM_PutFloat32I_swapped

#define EM_PutFloat64_be   EM_PutFloat64_native
#define EM_PutFloat64_le   EM_PutFloat64_swapped

#define EM_PutFloat64I_be  EM_PutFloat64I_native
#define EM_PutFloat64I_le  EM_PutFloat64I_swapped


#define EM_freadInt16_be  EM_freadInt16_native
#define EM_freadInt16_le  EM_freadInt16_swapped

#define EM_freadInt16_r_be  EM_freadInt16_r_native
#define EM_freadInt16_r_le  EM_freadInt16_r_swapped

#define EM_freadInt16P_be  EM_freadInt16P_native
#define EM_freadInt16P_le  EM_freadInt16P_swapped

#define EM_freadInt32_be  EM_freadInt32_native
#define EM_freadInt32_le  EM_freadInt32_swapped

#define EM_freadUInt32_be  EM_freadUInt32_native
#define EM_freadUInt32_le  EM_freadUInt32_swapped

#define EM_freadInt64_be  EM_freadInt64_native
#define EM_freadInt64_le  EM_freadInt64_swapped

#define EM_freadFloat16_be  EM_freadFloat16_native
#define EM_freadFloat16_le  EM_freadFloat16_swapped

#define EM_freadFloat32_be  EM_freadFloat32_native
#define EM_freadFloat32_le  EM_freadFloat32_swapped

#define EM_freadFloat64_be  EM_freadFloat64_native
#define EM_freadFloat64_le  EM_freadFloat64_swapped

#define EM_fwriteFloat16_be  EM_fwriteFloat16_native
#define EM_fwriteFloat16_le  EM_fwriteFloat16_swapped

#define EM_fwriteFloat32_be  EM_fwriteFloat32_native
#define EM_fwriteFloat32_le  EM_fwriteFloat32_swapped

#define EM_fwriteFloat64_be  EM_fwriteFloat64_native
#define EM_fwriteFloat64_le  EM_fwriteFloat64_swapped

#define EM_fwriteInt16_be  EM_fwriteInt16_native
#define EM_fwriteInt16_le  EM_fwriteInt16_swapped

#define EM_fwriteUInt16_be  EM_fwriteUInt16_native
#define EM_fwriteUInt16_le  EM_fwriteUInt16_swapped

#define EM_fwriteInt32_be  EM_fwriteInt32_native
#define EM_fwriteInt32_le  EM_fwriteInt32_swapped

#define EM_fwriteUInt32_be  EM_fwriteUInt32_native
#define EM_fwriteUInt32_le  EM_fwriteUInt32_swapped

#define EM_fwriteInt64_be  EM_fwriteInt64_native
#define EM_fwriteInt64_le  EM_fwriteInt64_swapped

#define EM_fwriteUInt64_be  EM_fwriteUInt64_native
#define EM_fwriteUInt64_le  EM_fwriteUInt64_swapped

#define EM_writeInt16_be  EM_writeInt16_native
#define EM_writeInt16_le  EM_writeInt16_swapped

#define EM_writeInt32_be  EM_writeInt32_native
#define EM_writeInt32_le  EM_writeInt32_swapped

#define EM_writeInt64_be  EM_writeInt64_native
#define EM_writeInt64_le  EM_writeInt64_swapped


#else  // Little endian


#define EM_GetFloat16_le  EM_GetFloat16_native
#define EM_GetFloat16_be  EM_GetFloat16_swapped

#define EM_GetFloat16I_le  EM_GetFloat16I_native
#define EM_GetFloat16I_be  EM_GetFloat16I_swapped

#define EM_GetFloat32_le  EM_GetFloat32_native
#define EM_GetFloat32_be  EM_GetFloat32_swapped

#define EM_GetFloat32I_le  EM_GetFloat32I_native
#define EM_GetFloat32I_be  EM_GetFloat32I_swapped

#define EM_GetFloat64_le  EM_GetFloat64_native
#define EM_GetFloat64_be  EM_GetFloat64_swapped

#define EM_GetFloat64I_le  EM_GetFloat64I_native
#define EM_GetFloat64I_be  EM_GetFloat64I_swapped

#define EM_PutFloat16_le   EM_PutFloat16_native
#define EM_PutFloat16_be   EM_PutFloat16_swapped

#define EM_PutFloat16I_le  EM_PutFloat16I_native
#define EM_PutFloat16I_be  EM_PutFloat16I_swapped

#define EM_PutFloat32_le   EM_PutFloat32_native
#define EM_PutFloat32_be   EM_PutFloat32_swapped

#define EM_PutFloat32I_le  EM_PutFloat32I_native
#define EM_PutFloat32I_be  EM_PutFloat32I_swapped

#define EM_PutFloat64_le   EM_PutFloat64_native
#define EM_PutFloat64_be   EM_PutFloat64_swapped

#define EM_PutFloat64I_le  EM_PutFloat64I_native
#define EM_PutFloat64I_be  EM_PutFloat64I_swapped


#define EM_freadInt16_le  EM_freadInt16_native
#define EM_freadInt16_be  EM_freadInt16_swapped

#define EM_freadInt16_r_le  EM_freadInt16_r_native
#define EM_freadInt16_r_be  EM_freadInt16_r_swapped

#define EM_freadInt16P_le  EM_freadInt16P_native
#define EM_freadInt16P_be  EM_freadInt16P_swapped

#define EM_freadInt32_le  EM_freadInt32_native
#define EM_freadInt32_be  EM_freadInt32_swapped

#define EM_freadUInt32_le  EM_freadUInt32_native
#define EM_freadUInt32_be  EM_freadUInt32_swapped

#define EM_freadInt64_le  EM_freadInt64_native
#define EM_freadInt64_be  EM_freadInt64_swapped

#define EM_freadFloat16_le  EM_freadFloat16_native
#define EM_freadFloat16_be  EM_freadFloat16_swapped

#define EM_freadFloat32_le  EM_freadFloat32_native
#define EM_freadFloat32_be  EM_freadFloat32_swapped

#define EM_freadFloat64_le  EM_freadFloat64_native
#define EM_freadFloat64_be  EM_freadFloat64_swapped

#define EM_fwriteFloat16_le  EM_fwriteFloat16_native
#define EM_fwriteFloat16_be  EM_fwriteFloat16_swapped

#define EM_fwriteFloat32_le  EM_fwriteFloat32_native
#define EM_fwriteFloat32_be  EM_fwriteFloat32_swapped

#define EM_fwriteFloat64_le  EM_fwriteFloat64_native
#define EM_fwriteFloat64_be  EM_fwriteFloat64_swapped

#define EM_fwriteInt16_le  EM_fwriteInt16_native
#define EM_fwriteInt16_be  EM_fwriteInt16_swapped

#define EM_fwriteUInt16_le  EM_fwriteUInt16_native
#define EM_fwriteUInt16_be  EM_fwriteUInt16_swapped

#define EM_fwriteInt32_le  EM_fwriteInt32_native
#define EM_fwriteInt32_be  EM_fwriteInt32_swapped

#define EM_fwriteUInt32_le  EM_fwriteUInt32_native
#define EM_fwriteUInt32_be  EM_fwriteUInt32_swapped

#define EM_fwriteInt64_le  EM_fwriteInt64_native
#define EM_fwriteInt64_be  EM_fwriteInt64_swapped

#define EM_fwriteUInt64_le  EM_fwriteUInt64_native
#define EM_fwriteUInt64_be  EM_fwriteUInt64_swapped

#define EM_writeInt16_le  EM_writeInt16_native
#define EM_writeInt16_be  EM_writeInt16_swapped

#define EM_writeInt32_le  EM_writeInt32_native
#define EM_writeInt32_be  EM_writeInt32_swapped

#define EM_writeInt64_le  EM_writeInt64_native
#define EM_writeInt64_be  EM_writeInt64_swapped



// File I/O
//
// Temporary variables for CPU byte order-independence macros
//

/*
extern EFloat16  _MFloat16;
extern float     _MFloat32;
extern double    _MFloat64;
extern uint8_t*  _MFloat16Ptr;
extern uint8_t*  _MFloat32Ptr;
extern uint8_t*  _MFloat64Ptr;
*/

#endif  // BIG_ENDIAN


#define EM_freadMatrixFloat32_be(pPtr, pFile) do\
{\
	EM_freadFloat32_be((pPtr)[M00], pFile);EM_freadFloat32_be((pPtr)[M01], pFile);EM_freadFloat32_be((pPtr)[M02], pFile);EM_freadFloat32_be((pPtr)[M03], pFile);\
	EM_freadFloat32_be((pPtr)[M10], pFile);EM_freadFloat32_be((pPtr)[M11], pFile);EM_freadFloat32_be((pPtr)[M12], pFile);EM_freadFloat32_be((pPtr)[M13], pFile);\
	EM_freadFloat32_be((pPtr)[M20], pFile);EM_freadFloat32_be((pPtr)[M21], pFile);EM_freadFloat32_be((pPtr)[M22], pFile);EM_freadFloat32_be((pPtr)[M23], pFile);\
	EM_freadFloat32_be((pPtr)[M30], pFile);EM_freadFloat32_be((pPtr)[M31], pFile);EM_freadFloat32_be((pPtr)[M32], pFile);EM_freadFloat32_be((pPtr)[M33], pFile);\
} while(0)

#endif	// defined(EM_GetInt16)


#define EEntityCore_Init(pEntity, pStatic) do\
{\
	EEntity*  lEntity = (EEntity*)(pEntity);\
	lEntity->Name = NULL;\
	lEntity->RefCnt=0;\
	lEntity->SelfRefCnt = 0;\
	lEntity->Static = pStatic;\
	lEntity->NameStatic = FALSE;\
	lEntity->BeingFreed = FALSE;\
} while(0)

#define EEntityCore_Free(pEntity) do\
{\
	if(!pEntity->NameStatic) EFreeChkClr(pEntity->Name);\
} while(0)


#ifndef E_BinarySearch
//================================================================================
// Binary search template function, debug version
//
// Arguments
//  pCount      Number of elements
//  pCmpFunc    Expression
//  pIndex      Index of resulting element
//
// Return value
//  pIndex will contain index to the CLOSEST matched element.
//  This version performs no equality check.
//  This macro is functionally equivalent to E_BinarySearch, except it prints
//  out debugging information, and it checks for duplicate comparisons.
//================================================================================
#define E_BinarySearchDbg(pCount, pCmpFunc, pIndex) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
EBool  lChecked[pCount + 10];memset(lChecked, 0, sizeof(lChecked));\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
if(lChecked[lGIndex]) { printf(" [%sALREADY CHECKED%s] %d\n", ECodeRed, ECodeNormal, (int)lGIndex);fflush(stdout);assert(0); }\
\
		if(pCmpFunc(lGIndex))\
		{\
lChecked[lGIndex] = TRUE;\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else\
			{\
/* If the segment length was even, the new upper half will be odd, as we just tested its 0th value. The beauty of the code below is that, when we  */\
/* are down to lSegmentLength = 2, this will make it 0, so we'll terminate (otherwise, we may end up checking the entry above the setment, twice). */\
/* This eliminates the need for additional testing for that situation.  */\
				lSegmentLength >>= 1;lSegmentLength--;\
			}\
\
			lSegmentBase += lIndexInSegment + 1;  /* Step up from the value we just tested (so, we don't test it again)  */\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
	pIndex = lSegmentBase + lIndexInSegment;\
printf("%s() %s:%d  lSegmentBase %d  lIndexInSegment %d\n", __FUNCTION__, __FILE__, __LINE__, (int)lSegmentBase, (int)lIndexInSegment);fflush(stdout);\
} while(0)



//================================================================
// Binary search template function
//
// Arguments
//  pCount      Number of elements
//  pCmpFunc    Comparison expression (e.g. MyArray[p] < blah)
//  pIndex      Index of resulting element
//
// Return value
//  pIndex will contain the index to the CLOSEST matched element.
//  This version does not perform equality checks.
//================================================================
#define E_BinarySearch(pCount, pCmpFunc, pIndex) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
\
		if(pCmpFunc(lGIndex))\
		{\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else\
			{\
/* If the segment length was even, the new upper half will be odd, as we just tested its 0th value. The beauty of the code below is that, when we  */\
/* are down to lSegmentLength = 2, this will make it 0, so we'll terminate (otherwise, we may end up checking the entry above the setment, twice). */\
/* This eliminates the need for additional testing for that situation.  */\
				lSegmentLength >>= 1;lSegmentLength--;\
			}\
\
			lSegmentBase += lIndexInSegment + 1;  /* Step up from the value we just tested (so, we don't test it again)  */\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
	pIndex = lSegmentBase + lIndexInSegment;\
} while(0)


//========================================================================================================
// Binary search template function
//
// Arguments
//  pCount         Number of elements
//  pAccessFunc    Function to access the element at a given index (e.g. MyArray[p])
//  pIndex         Index of resulting element
//
// Return value
//  pIndex will contain the index to the closest matched element.
//  This version performs equality checks, and if found, returns the index to the value equal to pValue
//========================================================================================================
#define E_BinarySearchEqq(pCount, pAccessFunc, pValue, pIndex) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
\
		if(pAccessFunc(lGIndex) == pValue) break;\
		else if(pAccessFunc(lGIndex) < pValue)\
		{\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else\
			{\
/* If the segment length was even, the new upper half will be odd, as we just tested its 0th value. The beauty of the code below is that, when we  */\
/* are down to lSegmentLength = 2, this will make it 0, so we'll terminate (otherwise, we may end up checking the entry above the setment, twice). */\
/* This eliminates the need for additional testing for that situation.  */\
				lSegmentLength >>= 1;lSegmentLength--;\
			}\
\
			lSegmentBase += lIndexInSegment + 1;  /* Step up from the value we just tested (so, we don't test it again)  */\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
	pIndex = lSegmentBase + lIndexInSegment;\
} while(0)
#endif


//================================================================================
// Binary search template function
//
// Arguments
//  pArray    Array of values to search
//  pCount    Number of elements in pArray
//  pValue    Value to look for
//  pIndex    The result
//
// Description
//  This version checks for equality and returns -1 if the item was not found.
//  It takes an array of atomic types (int, float etc.) as input.
//
// Return value
//  pIndex will contain the index to the matching element, or -1 if not found.
//================================================================================
#define E_BinarySearchEq(pArray, pCount,  pValue,  pIndex) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
	pIndex = -1;\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
\
		if(pArray[lGIndex] == pValue) { pIndex = lGIndex;break; }\
		if(pArray[lGIndex] < pValue)\
		{\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else { lSegmentLength >>= 1;lSegmentLength--; }\
			lSegmentBase += lIndexInSegment + 1;\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
} while(0)


//================================================================
// Binary search template function
//
// Arguments
//  pCount      Number of elements
//  pArray      Array of structs to search
//  pValue      Value to look for
//  pCmpFunc    Comparison procedure (like for qsort())
//  pIndex      Index of resulting element
//
// Description
//  This version checks for equality. If the item was not found, it returns -1 in pIndex.
//  It takes an array of atomic types (int, float etc.) or structs, Objects etc. and a comparison function as input.
//
// Return value
//  pIndex will contain index to matched element.
//================================================================
#define E_BinarySearchCmpEq(pArray, pCount,  pValue,  pCmpFunc,  pIndex) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
	pIndex = -1;\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
\
		const int  lCmpResult = pCmpFunc(pArray + lGIndex, pValue);\
		if(lCmpResult == 0) { pIndex = lGIndex;break; }\
		if(lCmpResult < 0)\
		{\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else { lSegmentLength >>= 1;lSegmentLength--; }\
			lSegmentBase += lIndexInSegment + 1;\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
} while(0)


//========================================================================
// Binary search template function, with insertion index returned.
//
// Arguments
//  pArray         Array of structs to search
//  pCount         Number of elements
//  pValue           Value to look for
//  pCmpFunc       Comparison procedure (like for qsort())
//  pIndex         Index of resulting element
//  pInsertHere    Where to insert the given element, if it was not found
//
// Description
//  This version checks for equality. If the item was not found, it returns:
//  - pIndex       -1
//  - pInsertHere  The position before which to insert the new element.
//  It takes an array of atomic types (int, float etc.) or structs, Objects etc. and a comparison function as input.
//
// Return value
//  pIndex will contain index to matched element.
//========================================================================
#define E_BinarySearchCmpEqIns(pArray, pCount,  pValue,  pCmpFunc, pIndex, pInsertHere) do\
{\
	EIndex  lSegmentBase = 0, lSegmentLength = pCount, lIndexInSegment = lSegmentLength >> 1;\
\
	pIndex = -1;\
	while(lSegmentLength > 0)\
	{\
		const EIndex  lGIndex = lSegmentBase + lIndexInSegment;\
\
		const int  lCmpResult = pCmpFunc(pArray + lGIndex, pValue);\
		if(lCmpResult == 0) { pIndex = lGIndex;break; }\
		if(lCmpResult < 0)\
		{\
			if(lSegmentLength & 1) lSegmentLength >>= 1;\
			else { lSegmentLength >>= 1;lSegmentLength--; }\
			lSegmentBase += lIndexInSegment + 1;\
		}\
		else lSegmentLength >>= 1;\
\
		lIndexInSegment = lSegmentLength >> 1;\
	}\
	pInsertHere = lSegmentBase + lIndexInSegment;\
} while(0)



#define E_system(p) do\
{\
	if(system(p) == -1)\
	{\
		printf("%s() %s:%d  system(p) failed\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);\
	}\
} while(0)


#define E_fgets(pS, pSize, pFile) do\
{\
	if(fgets(pS, pSize, pFile) == NULL)\
	{\
		printf("%s() %s:%d  fgets failed\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);\
	}\
} while(0)


#define E_fread(pP, pSize, pC, pFile) do\
{\
	const size_t  lC = fread(pP, pSize, pC, pFile);if(lC != pC)\
	{\
		printf("%s() %s:%d  length mismatch got %lld vs %lld at %lld\n", __FUNCTION__, __FILE__, __LINE__, (long long)lC, (long long)(pC), (long long)ftell(pFile));fflush(stdout);\
	}\
} while(0)


#define E_fwrite(pP, pSize, pC, pFile) do\
{\
	if(fwrite(pP, pSize, pC, pFile) != pC)\
	{\
		printf("%s() %s:%d  length mismatch\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);\
	}\
} while(0)


#define E_write(pFile, pP, pLength) do\
{\
	if(write(pFile, pP, pLength) != pLength)\
	{\
		printf("%s() %s:%d  length mismatch\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);\
	}\
} while(0)


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif


#ifndef EBoolTYPE
#ifdef CRAY
typedef long  EBool;
#else
typedef char	EBool;
#endif
#define EBoolTYPE
#endif  // EBoolTYPE

typedef struct
{
	EBool  X, Y;
} EBool2;

static inline EBool2 EBool2_s(const EBool PX, const EBool PY)
{
	const EBool2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}


// Define boolean values
//
#ifndef TRUE
#define TRUE   1
#endif
#ifndef FALSE
#define FALSE  0
#endif


typedef s_long64		ETime;
#define ECurrentTime  0

extern ETime  E_GetSeconds(void);
extern ETime  E_GetMilliseconds(void);
extern ETime  E_GetMicroseconds(void);
extern ETime  E_GetNanoseconds(void);

#define EBoolUNSPECIFIED  2
#define EBoolTOGGLE       3

// GUIProc actions
//
enum { E_CREATE = 1, E_UPDATE, E_CLOSE, E_DEACTIVATE, E_FREE };


typedef uint32_t	EChangeFlags;
typedef uint32_t	EUpdateFlags;
typedef uint32_t	ECallFlags;
typedef uint32_t	EFlags;

// Define an unsigned integer that is the same size as pointers
//
#if EPointer_BITS == 64
#define EPointerUInt  uint64_t
#define EPointerInt   int64_t
#else
#define EPointerUInt  unsigned int
#define EPointerInt   int
#endif




//
// System-dependent Definitions.
// The typedef of EArgVal should be chosen such that
//
//	sizeof(EArgVal) >= sizeof(EPointer)
//				sizeof(char*)
//				sizeof(long)
//				sizeof(int*)
//				sizeof(proc*)
//				sizeof(double)
//
#ifdef CRAY
typedef char*          EArgVal;
#else
typedef long           EArgVal;
//typedef uint64_t     EArgVal;  // This allows up to 64-bit pointers and double
#endif


typedef struct
{
	char*    Name;
	EArgVal  Value;
} EArg;


// Macro to get the offset of a field in a structure
//
#if defined(CRAY) || defined(__arm) || defined(__ACK)
#if __STDC__ && !defined(__ACK)
#define EOffset(p_type,field)  _Offsetof(p_type, field)
#else
#ifdef CRAY2
#define EOffset(p_type, field)  (sizeof(int) * ((unsigned int)&(((p_type)NULL)->field)))

#else  // !CRAY2

#define EOffset(p_type, field)  ((EPointerInt)&(((p_type)NULL)->field))

#endif  // !CRAY2
#endif  // __STDC__
#else   // ! (CRAY || __arm || __ACK)

#define EOffset(p_type, field)  ((EPointerInt)(((char*)(&(((p_type)NULL)->field))) - ((char*)NULL)))

#endif  // !CRAY

#ifdef offsetof
#define EOffsetOf(s_type, field)  offsetof(s_type, field)
#else
#define EOffsetOf(s_type, field)  EOffset(s_type*, field)
#endif


// Macro to get offset of a field in a structure as a pointer
//
#define EPtrOffset(p_type, field)  (EPointerUInt)(&(((p_type*)NULL)->field))

#define EOffsetToPtr(pStruct, pOffset) (((uint8_t*)pStruct) + pOffset)

// Macros equivalent to PStruct++, PStruct-- etc., but with support for a stride different than sizeof(*PStruct)
//
#define EStruct_Inc(p, pByteStride)               p = (typeof(p))((uint8_t*)(p) + pByteStride)
#define EStruct_Dec(p, pByteStride)               p = (typeof(p))((uint8_t*)(p) - pByteStride)
#define EStruct_Next(p, pByteStride)              ((typeof(p))((uint8_t*)(p) + (pByteStride)))
#define EStruct_Prev(p, pByteStride)              (typeof(p))((uint8_t*)(p) - pByteStride)
#define EStruct_ByIndex(p, pByteStride, pIndex)   ((typeof(p))((uint8_t*)(p) + pByteStride * (pIndex)))
#define EStruct_GetIndex(pArray, pByteStride, p)  ((uint8_t*)(p) - (uint8_t*)(pArray)) / (pByteStride)


#if EIndex_BITS == 64
	typedef int64_t    EIndex;
	typedef int64_t    ESize;
	typedef int64_t    EInt;
	typedef uint64_t   EUInt;
	#define E_Abs      llabs
#else
	typedef int           EIndex;
	typedef int           ESize;
	typedef int           EInt;
	typedef unsigned int  EUInt;
	#define E_Abs         abs
#endif

typedef unsigned int  EUnsignedInt;

typedef EIndex    EID;

typedef struct
{
	union { EIndex X;EIndex U; };
	union { EIndex Y;EIndex V; };
} EIndex2;

static inline EIndex2 EIndex2_s(const EIndex PX, const EIndex PY)
{
	const EIndex2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}


#define E_AddIndex2(pPoints, pCounter,  pX, pY) do\
{\
	(pPoints)[pCounter].X = pX;\
	(pPoints)[pCounter].Y = pY;\
	pCounter++;\
} while(0)


#ifdef __SSE2__
//#define	ESIMD  1
#endif


typedef struct
{
	EIndex  X, Y, Z;
} EIndex3;

static inline EIndex3 EIndex3_s(const EIndex PX, const EIndex PY, const EIndex PZ)
{
	const EIndex3  LResult = { .X= PX, .Y= PY, .Z= PZ };
	return(LResult);
}

typedef struct
{
	EIndex  X, Y, Z, W;
} EIndex4;

static inline EIndex4 EIndex4_s(const EIndex PX, const EIndex PY, const EIndex PZ, const EIndex PW)
{
	const EIndex4  LResult = { .X= PX, .Y= PY, .Z= PZ, .W= PW };
	return(LResult);
}


typedef struct
{
	int16_t  X, Y;
} EInt16_2;

static inline EInt16_2 EInt16_2_s(const int16_t PX, const int16_t PY)
{
	const EInt16_2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}


typedef struct
{
	uint16_t  X, Y, Z;
} EUInt16_3;

static inline EUInt16_3 EUInt16_3_s(const uint16_t PX, const uint16_t PY, const uint16_t PZ)
{
	const EUInt16_3  LResult = { .X= PX, .Y= PY, .Z= PZ };
	return(LResult);
}


typedef struct
{
	uint16_t  X, Y, Z, W;
} EUInt16_4;

static inline EUInt16_4 EUInt16_4_s(const uint16_t PX, const uint16_t PY, const uint16_t PZ, const uint16_t PW)
{
	const EUInt16_4  LResult = { .X= PX, .Y= PY, .Z= PZ, .W= PW };
	return(LResult);
}


typedef struct
{
	int32_t  X, Y;
} EInt32_2;

static inline EInt32_2 EInt32_2_s(const int32_t PX, const int32_t PY)
{
	const EInt32_2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}


typedef struct
{
	uint32_t  X, Y;
} EUInt32_2;

typedef struct
{
	int32_t  X, Y, Z;
} EInt32_3;

static inline EInt32_3 EInt32_3_s(const int32_t PX, const int32_t PY, const int32_t PZ)
{
	const EInt32_3  LResult = { .X= PX, .Y= PY, .Z= PZ };
	return(LResult);
}


#if ESIMD

typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
	float  unused0, unused1;
} EFloat32_2 __attribute__((aligned(16)));;

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
	double  unused0, unused1;
} EFloat64_2 __attribute__((aligned(32)));


typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
	union { float  Z;float z;float  B;float  b; };
	float  unused;
} EFloat32_3 __attribute__((aligned(16)));;

static inline EFloat32_3 EFloat32_3_s(const float PX, const float PY, const float PZ)
{
	const EFloat32_3  LV = { .X= PX, .Y= PY, .Z= PZ, .unused= 0.0 };
	return(LV);
}

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
	union { double  Z;double  z;double  B;double b; };
	double  unused0, unused1;
} EFloat64_3 __attribute__((aligned(32)));


typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
	union { float  Z;float z;float  B;float  b; };
	union { float  W;float w;float  A;float  a; };
} EFloat32_4 __attribute__((aligned(16)));;

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
	union { double  Z;double  z;double  B;double b; };
	union { double  W;double  w;double  A;double a; };
} EFloat64_4 __attribute__((aligned(32)));

#else // ESIMD

typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
} EFloat32_2;

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
} EFloat64_2;


typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
	union { float  Z;float z;float  B;float  b; };
} EFloat32_3;

static inline EFloat32_3 EFloat32_3_s(const float PX, const float PY, const float PZ)
{
	const EFloat32_3  LV = { .X= PX, .Y= PY, .Z= PZ };
	return(LV);
}

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
	union { double  Z;double  z;double  B;double b; };
} EFloat64_3;


typedef struct
{
	union { float  X;float x;float  R;float  r; };
	union { float  Y;float y;float  G;float  g; };
	union { float  Z;float z;float  B;float  b; };
	union { float  W;float w;float  A;float  a; };
} EFloat32_4;

typedef struct
{
	union { double  X;double  x;double  R;double r; };
	union { double  Y;double  y;double  G;double g; };
	union { double  Z;double  z;double  B;double b; };
	union { double  W;double  w;double  A;double a; };
} EFloat64_4;

#endif  // ESIMD


//----------------------------------------
// Vector type constructors
//----------------------------------------
static inline EFloat32_2 EFloat32_2s(const float PX, const float PY)
{
	const EFloat32_2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}

static inline EFloat64_2 EFloat64_2s(const double PX, const double PY)
{
	const EFloat64_2  LResult = { .X= PX, .Y= PY };
	return(LResult);
}


static inline EFloat32_3 EFloat32_3s(const float PX, const float PY, const float PZ)
{
	const EFloat32_3  LResult = { .X= PX, .Y= PY, .Z= PZ };
	return(LResult);
}

static inline EFloat64_3 EFloat64_3s(const double PX, const double PY, const double PZ)
{
	const EFloat64_3  LResult = { .X= PX, .Y= PY, .Z= PZ };
	return(LResult);
}


static inline EFloat32_4 EFloat32_4s(const float  PX, const float PY, const float  PZ, const float PW)
{
	const EFloat32_4  LResult = { .X= PX, .Y= PY, .Z= PZ, .W= PW };
	return(LResult);
}

static inline EFloat64_4 EFloat64_4s(const double PX, const double PY, const double PZ, const double PW)
{
	const EFloat64_4  LResult = { .X= PX, .Y= PY, .Z= PZ, .W= PW };
	return(LResult);
}


#define EInv255     0.0039215f
#define EInv256N    0.00390625f
#define E128N       127.9999f
#define E256N       255.9999f
#define E32768N     32767.99f
#define E65536N     65535.99f
#define EInv65536N  (1.0 / 65536.1)
#define EInv32768N  (1.0 / 32768.1)

#define EPI       3.14159265358979323846264
#define EInvPI    (1.0 / EPI)
#define	ERADIANS_TO_DEGREES  (180.0 / EPI)
#define EDEGREES_TO_RADIANS  (EPI / 180.0)



typedef void*  EPointer;


#define EM_SwapLong(p)  (((p & 0xFF000000) >> 24) | ((p & 0x00FF0000) >> 8) | ((p & 0x0000FF00) << 8) | ((p & 0x000000FF) << 24))

#define E_ABS(p)   (((p) < 0) ? (-p) : (p))
#define E_Sign(p)  (p < 0 ? -1 : 1)


typedef struct
{
	EIndex  Count;
} EChanges;

static inline void EChanges_Init(EChanges* PChange)
{
	PChange->Count = 0;
}

//========================================================
// Update PChanges1 from PChanges0
//========================================================
static inline void EChanges_Update(const EChanges* PChanges0, EChanges* PChanges1)
{
	PChanges1->Count = PChanges0->Count;
}

//========================================================
// Returns TRUE if PChanges0 is older than PChanges1
//========================================================
static inline EBool EChanges_Older(const EChanges* PChanges0, const EChanges* PChanges1)
{
	if(PChanges0->Count < PChanges1->Count) return(TRUE);
	return(FALSE);
}

//================================================================
// Returns TRUE if PChanges0 is newer or the same as PChanges1
//================================================================
static inline EBool EChanges_NewerOrSame(const EChanges* PChanges0, const EChanges* PChanges1)
{
	if(PChanges0->Count >= PChanges1->Count) return(TRUE);
	return(FALSE);
}

static inline void EChanges_Bump(EChanges* PChange)
{
	PChange->Count++;
}


#ifndef EFLOAT16
#define EFLOAT16
typedef short  EFloat16;
#endif


// Temporary variables for CPU byte order-independence macros
//

extern EFloat16  _MFloat16;
extern float     _MFloat32;
extern double    _MFloat64;
extern uint8_t*  _MFloat16Ptr;
extern uint8_t*  _MFloat32Ptr;
extern uint8_t*  _MFloat64Ptr;


// High-range fixed-point value
//
typedef struct
{
	int  P18, P9, P0, PM9;  // Powers of 10: 18, 9, 0, -9
} EFixed;



// CPU types
//
enum
{
	ECPU_UNKNOWN = 0,
	ECPU_MIPS_R5000,
	ECPU_MIPS_R5900,
	ECPU_MIPS_R8000,
	ECPU_MIPS_R10000,
	ECPU_PENTIUM2,
	ECPU_PENTIUM3,
	ECPU_PENTIUM4,
	ECPU_ITANIUM,
	ECPU_ATHLON,
	ECPU_DEC_ALPHA,
	ECPU_G4
};


// Function return values.
// 0 means success
// Negative numbers indicate an error, so
// Positive numbers may be used as normal return values.
//
// Use enum, rather than #define to make the compiler check for duplicates
typedef enum
{
	E_SUCCESS                       =   0,

	E_UNKNOWN_ERROR                 =  -2,

	E_NOT_SET                       =  -3,
	E_YES                           =  -4,
	E_NO                            =  -5,

// Data
	E_NO_DATA                       = -10,
	E_NO_DICTIONARY                 = -11,
	E_NO_NEW_DATA                   = -12,
	E_INCOMPATIBLE_DATA             = -13,    // E.g. an IOFilter can't save the given type of data (e.g. you can't save a hierarchy into a'.obj' file, or an RGBf32 image into JPEG)
	E_PREMATURE_END_OF_DATA         = -14,
	E_CORRUPT_DATA                  = -15,
	E_NO_DESTINATION                = -16,
	E_NO_OUTPUT                     = -17,    // No output specified
	E_OVERFLOW                      = -18,
	E_UNDERFLOW                     = -19,
	E_EMPTY_LIST                    = -20,
	E_INVALID_PARAMETERS            = -21,
	E_ALREADY_EXISTS			          = -22,
	E_OUT_OF_RANGE				          = -23,
	E_TOO_SMALL                     = -24,
	E_TOO_LARGE                     = -25,
	E_MISMATCH                      = -26,
	E_RESULT_APPROXIMATE            = -27,    // The result was approximated / indirectly recomputed
	E_RENAMED                       = -28,
	E_REMOVED                       = -29,
	E_SELECTED                      = -30,
	E_UNSELECTED                    = -31,
	E_ANY                           = -32,

// Features
	E_NOT_RECOGNIZED                = -40,    // Identifier etc. not recognized. E.g. when reading a file
	E_NOT_SUPPORTED                 = -41,    // Functionality not supported
	E_NOT_IMPLEMENTED               = -42,    // Functionality not implemented yet
	E_NOT_INCLUDED                  = -43,    // Functionality not included in linked binary, when using a *Dummy.c/o file
	E_NOT_LOADED                    = -44,    // Plugin for functionality not loaded
	E_DISABLED                      = -45,    // Feature disabled (e.g. temporarily)

	E_COULD_NOT_INITIALIZE          = -50,

// Memory
	E_NO_MEMORY                     = -60,
	E_NO_TRACKER                    = -61,
	E_DO_NOT_FREE                   = -62,    // Object-destructor return code
	E_FREED                         = -63,    // Object was already freed

// Process
	E_DONE                          = -70,    // Operation completed inside called funcion, no further processing needed (sometimes there is an important distinction between DONE and SUCCESS)
	E_NOTHING_TO_DO                 = -71,
	E_UPDATED                       = -72,
	E_TAKEN                         = -73,
	E_NO_CHANGE                     = -74,
	E_TRY_AGAIN                     = -75,
	E_BUSY                          = -76,
	E_TIMEOUT                       = -77,
	E_NO_PERMISSION                 = -78,
	E_IN_USE                        = -79,
	E_STOP                          = -80,    // User intervention
	E_STOPPED                       = -81,
	E_CANCELLED                     = -82,
	E_IN_PROGRESS                   = -83,    // E.g. a function spawned a new thread and returned to the caller

// Programs
	E_NO_PROGRAM                    = -400,    // No valid, compiled program available to perform operation
	E_COMPILE_ERROR                 = -401,
	E_LINK_ERROR                    = -402,
	E_UNDEFINED_SYMBOL              = -403,

// Files
	E_NO_READ_PERMISSION            = -100,
	E_NO_SEARCH_PERMISSION_FOR_DIR  = -101,
	E_NO_WRITE_PERMISSION_FOR_DIR	  = -102,
	E_NO_WRITE_PERMISSION_FOR_FILE  = -103,

	E_NO_FILENAME                   = -110,
	E_NO_FILE_EXTENSION             = -111,
	E_COULD_NOT_OPEN_FILE           = -112,
	E_COULD_NOT_OPEN_DIRECTORY      = -113,
	E_SEEK_ERROR                    = -114,
	E_READ_ERROR                    = -115,
	E_WRITE_ERROR                   = -116,
	E_NOT_A_NORMAL_FILE             = -117,
	E_DIRECTORY                     = -118,
	E_DIRECTORY_NOT_EMPTY           = -119,
	E_NO_SUCH_FILE_OR_DIRECTORY     = -120,
	E_NO_SUCH_FILE                  = -121,
	E_NO_SUCH_DIRECTORY             = -122,
	E_FILE_EXISTS                   = -123,
	E_NO_SPACE                      = -124,
	E_DESCRIPTOR_FILE_ERROR         = -125,
	E_UNSUPPORTED_OPERATION         = -126,    // E.g. an IOFilter can't write the given file (e.g. it can only read, but not write)
	E_UNSUPPORTED_FORMAT            = -127,    // E.g. an IOFilter can't read the given file (e.g. the Hierarchy reader can't read a 3D scene file)
	E_UNRECOGNIZED_FORMAT           = -128,    // E.g. an IOFilter can't open the given file
	E_NO_IOFILTER_FOUND             = -129,    // If the format is specified as FROM_EXTENSION...
	E_FILE_ALREADY_LOADED           = -130,
	E_CORRUPT_FILE                  = -131,
	E_UNSUPPORTED_SOURCE            = -132,    // E.g. an IOFilter can't read from a memory block, only from a file
	E_UNSUPPORTED_DESTINATION       = -133,    // E.g. an IOFilter can't write to a memory block, only to a file
	E_NOTHING_TO_SAVE               = -134,
	E_UNRELSOLVABLE_LINK            = -135,
	E_CAN_NOT_GET_DIRINFO           = -136,
	E_NFS_DIRECTORY                 = -137,
	E_NOT_FOUND                     = -138,
	E_BAD_FILE_DESCRIPTOR           = -139,
	E_FILE_TOO_LARGE_FOR_APP        = -140,
	E_END_OF_FILE                   = -141,

// Network and other interfaces
	E_NO_SUCH_DEVICE                = -200,
	E_COULD_NOT_CONNECT             = -201,
	E_NOT_CONNECTED                 = -202,
	E_ALREADY_CONNECTED             = -203,
	E_NO_BANDWIDTH                  = -204,    // No bandwidth left on device or communication interface
	E_INCOMPATIBLE_DEVICE           = -205,

// GUI
	E_CLIPPED                       = -500,
	E_COULD_NOT_CREATE_WINDOW       = -501,
	E_INVALID_WINDOW                = -502,
	E_NO_TARGET_IMAGE               = -503,
	E_NO_CAMERA                     = -504,

	E_IMAGE_TOO_SMALL               = -600,
	E_IMAGE_WRONG_ASPECT_RATIO      = -601
} EResult;



enum
{
	E_FILE = 1,
	E_SYMBOLIC_LINK,
	E_CHARACTER_DEVICE,
	E_BLOCK_DEVICE
};


#define EfCOLOR  0x0001  // Use terminal color codes

#define ENamedCore\
	char*     Name

//
// Base class for named/reference-counted things
//
// See also EObject
//
#define EEntityCore\
	ENamedCore;\
	int       RefCnt;\
	int       SelfRefCnt;      /* Destructor should be called, even if RefCnt is > 0 to check for self-reference / loop. */\
	uint32_t  Static:1,        /* Statically allocated Entity (e.g. an inlined icon Image).                           */\
            NameStatic:1,    /* Name is static (e.g. a global semantic ID). Don't free it                           */\
	          BeingFreed:1     /* Entity is being freed. This allows for avoiding infinite loops when cross-referenced Entities are freed, as well as memory corruption when multithreading is used.  */\

typedef struct
{
	EEntityCore;
} EEntity;


enum
{
	EOptimizeMEMORY = 1,
	EOptimizeSPEED
};


#define EREAD   0x01
#define EWRITE  0x02


#define EArrayCore(pType)\
	pType*  Items;EIndex  Count

// List type macro
//
#define EList_t(pType)\
typedef struct\
{\
	EArrayCore(pType);\
} pType##List

// List type macro for lazy-grow lists
//
#define EListA_t(pType)\
typedef struct\
{\
	EArrayCore(pType);\
	EIndex  CountAllocated;\
} pType##ListA



#define ERandomState  uint32_t

typedef struct
{
	ERandomState  RandomState[5];
} ERandom;

// Paralell-processing modes
// Numbers > 1 mean, run in as many threads as given
enum
{
	EThreadsAUTO = 0,   // Use as many threads as there are hardware threads
	EThreadsSINGLE = 1   // Run in single-threaded mode
};


enum
{
	EUp = 1,
	EDown
};

enum
{
	ERight = 1,
	ELeft
};

#define E_Max(a, b)  ((a) > (b) ? (a) : (b))
#define E_Min(a, b)  ((a) < (b) ? (a) : (b))
#define E_Clamp(pV,  pMin, pMax)  (pV < pMin ? pMin : (pV > pMax ? pMax : pV))

#define E_MaxXYZ_s(p)  (p).X > (p).Y ? ((p).X > (p).Z ? (p).X : (p).Z) : ((p).Y > (p).Z ? (p).Y : (p).Z)

#define E_Clamp3_s(pV, pMin, pMax)   { E_Clamp((pV).X, (pMin).X, (pMax).X), E_Clamp((pV).Y, (pMin).Y, (pMax).Y), E_Clamp((pV).Z, (pMin).Z, (pMax).Z) }

#define  _CRString "(C) 1996-2026 by Gabor Nagy (www.equinox3d.com)"

typedef uint32_t                    EPackedBool;
#define EPackedBoolBits            32
#define EPackedBoolBitShift         5
#define EPackedBoolBitShiftMask  0x1F


// When identifying a file's type (via "magic numbers etc.), try to read this many bytes
#define EFileFORMAT_ID_LENGTH  64


static inline void EPackedBool_FlagSet(EPackedBool* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> EPackedBoolBitShift, LBit = PIndex & EPackedBoolBitShiftMask;
	PFlags[LIndex] |= 1 << LBit;
}

static inline void EPackedBool_FlagClear(EPackedBool* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> EPackedBoolBitShift, LBit = PIndex & EPackedBoolBitShiftMask;
	PFlags[LIndex] &= ~(1 << LBit);
}

static inline EBool EPackedBool_FlagIsSet(const EPackedBool* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> EPackedBoolBitShift, LBit = PIndex & EPackedBoolBitShiftMask;
	return((PFlags[LIndex] & 1 << LBit) != 0);
}


//----------------------------------------------------------------------------------------
// Bit array operations. This allows a compact representation of large Bool arrays
//----------------------------------------------------------------------------------------
static inline void E_Flag8Set(uint8_t* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> 3, LBit = PIndex & 0x07;
	PFlags[LIndex] |= 1 << LBit;
}

static inline void E_Flag8Clear(uint8_t* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> 3, LBit = PIndex & 0x07;
	PFlags[LIndex] &= ~(1 << LBit);
}

static inline EBool E_Flag8IsSet(const uint8_t* PFlags, const EIndex PIndex)
{
	const EIndex  LIndex = PIndex >> 3, LBit = PIndex & 0x07;
	return((PFlags[LIndex] & 1 << LBit) != 0);
}

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration
#endif


#define E_THREAD_LOCK(p)    pthread_mutex_lock(&(p##_mutex))
#define E_THREAD_UNLOCK(p)  pthread_mutex_unlock(&(p##_mutex))

#define E_PushField_p(pStruct, pField)  const typeof(pStruct->pField) LTmp##pField = pStruct->pField
#define E_PopField_p(pStruct, pField)   pStruct->pField = LTmp##pField


#endif // _ETypes_h
