//========================================================================================================
// Reflective Object-Oriented framework
//
// - Meta-class and object templates
// - Object constructor, copy-constructor and destructor templates
// - GUI templates
// - Optional garbage collector with Object creation / freeing and reference tracking
//  ETODO
//  - Make Reference tracking (debug mode) thread-safe. Create a mutex and add locks around _EM_ObjectMemDebugAdd etc.
//  Note: for performance reasons, New/Delete etc. are not automatically protected by mutexes
//  You need to do it in your code!
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Aug-02 01:00:21
//
// Copyright (C) 1996-2026 By Gabor Nagy. All rights reserved.
//========================================================================================================
#ifndef _EClass_h
#define _EClass_h

#include <EParam.h>

#ifndef _ELists_h
#include <ELists.h>
#endif

#ifndef _EResource_h
#include <EResource.h>
#endif


// Enable full object reference tracking ("who is referencing whom?"), rather than just reference counting. Only use for debugging. Turn it off for release builts, to improve performance / reduce memory use.
// Requires a full rebuild.
// Enable EBACKTRACE in EMalloc.h for full call-stacks
//
#define EObjectMEMORY_DEBUG  0

#define EClassDEBUG          0

// Flags for EM_ObjectCopyTF
#define ECopyNAME      0x0001    // Copy Object name

extern pthread_mutex_t  EObject_mutex;
extern pthread_mutex_t  _E_Objects_mutex;

#if EObjectMEMORY_DEBUG
#include <pthread.h>
	#define	EObjectDOUBLEFREE_CHECK  1  // It should be defined, only, if EObjectMEMORY_DEBUG is enabled

	#define EObjectTHREAD_LOCK(p)    pthread_mutex_lock(&p##_mutex)
	#define EObjectTHREAD_UNLOCK(p)  pthread_mutex_unlock(&p##_mutex)
//	#define EObjectTHREAD_LOCK(p)    do { printf("%s() %s:%d LI", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);pthread_mutex_lock(&p##_mutex);  printf("%s() %s:%d LO\n", __FUNCTION__, __FILE__, __LINE__); } while(0)
//	#define EObjectTHREAD_UNLOCK(p)  do { printf("%s() %s:%d UI", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);pthread_mutex_unlock(&p##_mutex);printf("%s() %s:%d UO\n", __FUNCTION__, __FILE__, __LINE__); } while(0)
#else
	#define EObjectTHREAD_LOCK(p)
	#define EObjectTHREAD_UNLOCK(p)
#endif

#define	EMemDbgOBJECT_INIT         0x01
#define	EMemDbgSTATIC_OBJECT_INIT  0x02

//	pthread_mutex_init(&DEM_UpdateMutex, 0);
//	pthread_mutex_destroy(&DEM_UpdateMutex);


typedef const void*  cvoidp;
typedef EIndex       EObjectID;

// Component flags
//
#define EComponentCOPY                     0x0001  // Copy it when an Object with this Component is copied
#define EComponentSAVE                     0x0002  // Save it when an Object with this Component is saved
#define EComponentVISIBLE                  0x0004  // Show it in the GUI
#define EComponentEDITABLE                 0x0008  // Editable by the user
#define EComponentREMOVABLE                0x0010  // Removable by the user

#define EComponentANIMATABLE               0x0020  // Resources can be animated
#define EComponentRESPOND_TO_INPUT_CHANGE  0x0080

// This indicates that the Flags field was set by the caller to *ComponentClassRegister() (so we can distinguish an intended 0 value for the rest of the flags from no initialization).
// If this flag and all the others are 0, the flags were not initialized and will be set to EComponentDEFAULT by *ComponentClassRegister()
#define EComponentSET                      0x8000

#define EComponentDEFAULT                  (EComponentCOPY|EComponentSAVE|EComponentVISIBLE|EComponentEDITABLE|EComponentREMOVABLE)


#if EObjectMEMORY_DEBUG
extern void  _ELst_ArrayReferencesRemap(const cvoidp* PListOld, void** PList, const EIndex PN);
 #define _ELst_Remap(pListOld, pList, pCount) { if((void*)(pList) != (void*)(pListOld)) _ELst_ArrayReferencesRemap((const cvoidp*)(pListOld), (void**)(pList), pCount); }
#else
 #define _ELst_Remap(pListOld, pList, pCount)
#endif	// EObjectMEMORY_DEBUG



#if EObjectMEMORY_DEBUG

#ifndef EMalloc_h
#include <EMalloc.h>
#endif	// EMalloc_h

//================================================================
// Assign debugging name to Object if it doesn't have a name
//================================================================
#define EM_ObjectDebugName(pObject, pName) do\
{\
	if(pObject->Name == NULL) EObject_SetName(pObject, EStrDup(pName), FALSE);\
} while(0)

#define EM_ObjectDebugNameM_s(pObject) do\
{\
	if(pObject.Name == NULL) EObject_SetName(&(pObject), EStrDup(#pObject), FALSE);\
} while(0)

#define EM_ObjectDebugNameM_p(pObject) do\
{\
	if(pObject->Name == NULL) EObject_SetName(pObject, EStrDup(#pObject), FALSE);\
} while(0)

#define _EM_ObjectPrint(pObject, pVerbosityMask) do\
{\
	if(EMemDbg_Verbosity & pVerbosityMask)\
	{\
		printf("%s() %s:%d %p {%s} [%s%s%s]\n", __FUNCTION__, __FILE__, __LINE__, pObject, pObject->Class->Name, ECodeGreen, pObject->Name, ECodeNormal);fflush(stdout);\
	}\
} while(0)

	#include <assert.h>
	#ifndef _ELists_h
	#include <ELists.h>
	#endif

	#define _EM_ObjectMemDebugAdd(pObject, pArray) do\
	{\
EObjectTHREAD_LOCK(_E_Objects);\
		EObjectMemEntry*  lEntry = EList_StructAddA(_E_##pArray##Objects, 1024);\
		lEntry->Object = (ECoreObject*)(pObject);\
		lEntry->ObjectName = EStrDup((pObject)->Name);    /* Store the Object name, in case the Object is freed / damaged.  */\
\
		{\
			ECoreClass*  lllClass = (ECoreClass*)(pObject->Class);\
			lEntry->Class = lllClass;                            /* Store the Class, in case the Object gets damaged.              */\
			lEntry->ClassName = EClass_GetFullName(lllClass);    /* Store the Class name, in case the Class is freed.              */\
		}\
\
		EList_InitA(lEntry->References);\
\
		ECallerInfo*  lCaller = &lEntry->Creation;\
		lCaller->FileName = __FILE__;\
		lCaller->Function = __FUNCTION__;\
		lCaller->Line = __LINE__;\
		lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
		memset(&lEntry->Freeing, 0, sizeof(ECallerInfo));\
EObjectTHREAD_UNLOCK(_E_Objects);\
	} while(0)

	#ifdef EObjectDOUBLEFREE_CHECK

	  #define _M_StaticObjectsCheck(pObject)\
		if(!lFound)\
		{\
			if(EMemDbg_TrackStaticObjects)\
			{\
				const EIndex  lIndex = EList_PointerGetIndex(_E_StaticObjects, pObject);if(lIndex >= 0)\
				{\
					printf("%s() %s:%d  %s%p {%s} static Object.%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeCyan, pObject, lEntry->ClassName, ECodeNormal);fflush(stdout);\
					lFound = TRUE;\
				}\
			}\
			else lFound = TRUE;\
		}

		#define _M_FreedObjectsAddTo(pEntry) do\
		{\
			EObjectMemEntry*  lFEntry = EList_StructAddA(_E_FreedObjects, 64);\
			*lFEntry = *pEntry;\
		} while(0)

		#define _M_FreedObjectsCheck(pObject) do\
		{\
			if(!lFound)\
			{\
				const EIndex  lIndex = EList_PointerGetIndex(_E_FreedObjects, pObject);if(lIndex >= 0)\
				{\
					lEntry = _E_FreedObjects + lIndex;\
					printf("%s() %s:%d  %s%p {%s} double-free attempt.%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeRed, pObject, lEntry->ClassName, ECodeNormal);fflush(stdout);\
					lFound = TRUE;\
				}\
				else\
				{\
					printf("%s() %s:%d %sObject %p {%s} [%s] not found!%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeRed, pObject, pObject->Class->Name, pObject->Name, ECodeNormal);fflush(stdout);\
					assert(0);\
				}\
			}\
		} while(0)

	#else	// EObjectDOUBLEFREE_CHECK

		#define _M_FreedObjectsAddTo(pEntry)
		#define _M_FreedObjectsCheck(pObject)

	#endif	// EObjectDOUBLEFREE_CHECK



	#define _EM_ObjectMemDebugDel(pObject) do\
	{\
		ECoreObject*  lObject = (ECoreObject*)(pObject);\
EObjectTHREAD_LOCK(_E_Objects);\
		int  lI = 0;EBool  lFound = FALSE;EObjectMemEntry*  lEntry = _E_Objects;for(;lI < _E_Objects_Count;lI++, lEntry++)\
		{\
			if(lEntry->Object == lObject)\
			{\
				if(lEntry->References_Count > 0)\
				{\
					if(EMemDbg_BadRefResponse & E_PRINT)\
					{\
						printf("%sAttempting to free Object that still has references:%s\n", ECodeRed, ECodeNormal);fflush(stdout);\
						printf("%s%s() %s:%d%s\n", ECodeYellow, __FUNCTION__, __FILE__, __LINE__, ECodeNormal);fflush(stdout);\
						const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;_EObject_PrintReferences(lEntry, FALSE, lExecutableNameLen, TRUE);\
					}\
					if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
				}\
				else\
				{\
					EList_FreeAChk(lEntry->References);\
\
					{\
						ECallerInfo*  lCaller = &lEntry->Freeing;\
						lCaller->FileName = __FILE__;\
						lCaller->Function = __FUNCTION__;\
						lCaller->Line = __LINE__;\
						lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
						_M_FreedObjectsAddTo(lEntry);\
					}\
\
					EList_StructRemoveByIndexNoRealloc(_E_Objects, lI);\
				}\
\
				lFound = TRUE;\
				break;\
			}\
		}\
EObjectTHREAD_UNLOCK(_E_Objects);\
	 \
		_M_StaticObjectsCheck(lObject);\
		_M_FreedObjectsCheck(lObject);\
	} while(0)


	#define _M_ObjectEntryCheckRef(pObject, pEntry) do\
	{\
		if(EMemDbg_BadRefResponse)\
		{\
			if(pObject->RefCnt != pEntry->References_Count)\
			{\
				if(EMemDbg_BadRefResponse & E_PRINT)\
				{\
					printf("%s%s() %s:%d%s  Object has incorrect RefCnt:\n", ECodeYellow, __FUNCTION__, __FILE__, __LINE__, ECodeNormal);fflush(stdout);\
					const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;_EObject_PrintReferences(pEntry, FALSE, lExecutableNameLen, TRUE);\
				}\
				if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
			}\
			else if(pObject->RefCnt<0)\
			{\
				if(EMemDbg_BadRefResponse & E_PRINT)\
				{\
					printf("%s%s() %s:%d%s  Object has negative RefCnt:\n", ECodeYellow, __FUNCTION__, __FILE__, __LINE__, ECodeNormal);fflush(stdout);\
					const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;_EObject_PrintReferences(pEntry, FALSE, lExecutableNameLen, TRUE);\
				}\
				if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
			}\
		}\
	} while(0)


	#define EM_ObjectClassRemoved(pClass) do\
	{\
		{\
EObjectTHREAD_LOCK(_E_Objects);\
			const ECoreClass*  lClass = (ECoreClass*)(pClass);\
\
			EIndex  lI = 0;EObjectMemEntry*  lEntry = _E_Objects;for(;lI < _E_Objects_Count;lI++, lEntry++)\
			{\
				if(lEntry->Class == lClass)\
				{\
					lEntry->Object->Class = NULL;\
					lEntry->Class = NULL;\
				}\
			}\
		}\
\
		{\
			const ECoreClass*  lClass = (ECoreClass*)(pClass);\
\
			EIndex  lI = 0;EObjectMemEntry*  lEntry = _E_StaticObjects;for(;lI < _E_StaticObjects_Count;lI++, lEntry++)\
			{\
				if(lEntry->Class == lClass)\
				{\
					lEntry->Object->Class = NULL;\
					lEntry->Class = NULL;\
				}\
			}\
		}\
EObjectTHREAD_UNLOCK(_E_Objects);\
	} while(0)


#define _M_Ref(pAddressString, pDstObject,pDstMemberName,pResourceName)\
	EObjectReference  lReference;\
	lReference.AddressString = (char*)(#pAddressString);\
	lReference.ReferringObject = (ECoreObject*)pDstObject;lReference.ReferringMemberName = pDstMemberName;lReference.ResourceName = pResourceName;\
	ECallerInfo*  lCaller = &lReference.Caller;\
	lCaller->FileName = __FILE__;\
	lCaller->Function = __FUNCTION__;\
	lCaller->Line = __LINE__


//
// Suffixes:
// _om : object member
// _r  : return value
//


//========================================================================
// Add one Object pointer to a dynamically allocated pointer-array
//
// The array is checked to see if the Object is already listed.
// _om_ suffix means object-member reference tracking
// _r suffix means success boolean returned
//========================================================================
#define ELst_ObjectAdd(pListPtr, pNPointers, pObject) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);\
	_ELstMD_ObjectAdd(pListPtr, pNPointers, pObject, &lReference);\
} while(0)

#define ELst_ObjectAdd_r(pListPtr, pNPointers, pObject, pRet) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);\
	pRet = _ELstMD_ObjectAdd(pListPtr, pNPointers, pObject, &lReference);\
} while(0)

#define ELst_ObjectAdd_om(pDstObject,pDstMember, pObject) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	_ELstMD_ObjectAdd(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject, &lReference);\
} while(0)


#define ELst_ObjectAdd_om_s(pDstObject,pDstMember, pObject) do\
{\
	_M_Ref(pDstObject->pDstMember.Items, pDstObject,#pDstMember,NULL);\
	_ELstMD_ObjectAdd(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject, &lReference);\
} while(0)


#define ELst_ObjectAdd_om_r(pDstObject,pDstMember, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAdd(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject, &lReference);\
} while(0)

#define ELst_ObjectAdd_om_s_r(pDstObject,pDstMember, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember.Items, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAdd(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject, &lReference);\
} while(0)

#define ELst_ObjectAddChk(pListPtr, pNPointers, pObject) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);_ELstMD_ObjectAddChk(pListPtr, pNPointers, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddChk_r(pListPtr, pNPointers, pObject, pRet) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);pRet = _ELstMD_ObjectAddChk(pListPtr, pNPointers, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddChk_om(pDstObject,pDstMember, pObject) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);_ELstMD_ObjectAddChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject, &lReference);\
} while(0)

#define ELst_ObjectAddChk_om_r(pDstObject,pDstMember, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAddChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject, &lReference);\
} while(0)

#define ELst_ObjectAddChk_om_s_r(pDstObject,pDstMember, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember.Items, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAddChk(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject, &lReference);\
} while(0)

#define ELst_ObjectInsertChk_om_r(pDstObject,pDstMember, pWhere, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, NULL,NULL,NULL);\
	pRet = _ELstMD_ObjectInsertChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pWhere, pObject, &lReference);\
} while(0)



#define ELst_ObjectAddA(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);_ELstMD_ObjectAddA(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddA_om_sm(pDstObject,pDstOMember, pDstStruct,pDstMember, pAllocStep, pObject) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstOMember,NULL);\
	_ELstMD_ObjectAddA(&(pDstStruct->pDstMember), &(pDstStruct->pDstMember##_Count), &(pDstStruct->pDstMember##_CountAllocated), pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddA_om(pDstObject,pDstMember, pAllocStep, pObject) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	_ELstMD_ObjectAddA(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddA_s_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAddA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddAChk_s_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, pDstObject,#pDstMember,NULL);\
	pRet = _ELstMD_ObjectAddAChk(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pObject, &lReference);\
} while(0)


//========================================================================================================================
// Return value
//  E_DONE if successful, if pObject is already in pListPtr, it returns the index, or an error code in case of an error
//========================================================================================================================
#define ELst_ObjectInsertA_s_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, NULL,NULL,NULL);\
	pRet = _ELstMD_ObjectInsertA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pWhere, pObject, &lReference);\
} while(0)

#define ELst_ObjectInsertAChk_s_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, NULL,NULL,NULL);\
	pRet = _ELstMD_ObjectInsertAChk(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pWhere, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject,  pResult) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);\
	pResult = _ELstMD_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddAChk_r(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject, pRet) do\
{\
	_M_Ref(pListPtr, NULL,NULL,NULL);pRet = _ELstMD_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectAddAChk_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, NULL,NULL,NULL);pRet = _ELstMD_ObjectAddAChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pObject, &lReference);\
} while(0)

#define ELst_ObjectInsertAChk_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet) do\
{\
	_M_Ref(pDstObject->pDstMember, NULL,NULL,NULL);\
	pRet = _ELstMD_ObjectInsertAChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pWhere, pObject, &lReference);\
} while(0)

#else	// EObjectMEMORY_DEBUG

	#define EM_ObjectDebugName(pObject, pName)
	#define EM_ObjectDebugNameM_s(pObject)
	#define EM_ObjectDebugNameM_p(pObject)
	#define _EM_ObjectPrint(pObject, pVerbosityMask)
	#define _EM_ObjectMemDebugAdd(pObject, pArray)
	#define _EM_ObjectMemDebugDel(p)
	#define EM_ObjectClassRemoved(pClass)

	#define ELst_ObjectAdd(pListPtr, pNPointers, pObject)                 _ELst_ObjectAdd(pListPtr, pNPointers, pObject)
	#define ELst_ObjectAdd_r(pListPtr, pNPointers, pObject, pRet)  pRet = _ELst_ObjectAdd(pListPtr, pNPointers, pObject)
	#define ELst_ObjectAdd_om(pDstObject,pDstMember, pObject)                 _ELst_ObjectAdd(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
	#define ELst_ObjectAdd_om_s(pDstObject,pDstMember, pObject)               _ELst_ObjectAdd(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject)
	#define ELst_ObjectAdd_om_r(pDstObject,pDstMember, pObject, pRet)  pRet = _ELst_ObjectAdd(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
	#define ELst_ObjectAdd_om_s_r(pDstObject,pDstMember, pObject, pRet)  pRet = _ELst_ObjectAdd(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject)

	#define ELst_ObjectAddChk(pListPtr, pNPointers, pObject)                 _ELst_ObjectAddChk(pListPtr, pNPointers, pObject)
	#define ELst_ObjectAddChk_r(pListPtr, pNPointers, pObject, pRet)  pRet = _ELst_ObjectAddChk(pListPtr, pNPointers, pObject)
	#define ELst_ObjectAddChk_om(pDstObject,pDstMember, pObject)                 _ELst_ObjectAddChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
	#define ELst_ObjectAddChk_om_r(pDstObject,pDstMember, pObject, pRet)  pRet = _ELst_ObjectAddChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
	#define ELst_ObjectAddChk_om_s_r(pDstObject,pDstMember, pObject, pRet)  pRet = _ELst_ObjectAddChk(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject)

	#define ELst_ObjectInsertChk_om_r(pDstObject,pDstMember, pWhere, pObject, pRet)  pRet = _ELst_ObjectInsertChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pWhere, pObject)

	#define ELst_ObjectAddA(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject)             _ELst_ObjectAddA(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject)
	#define ELst_ObjectAddA_om_sm(pDstObject,pDstOMember, pDstStruct,pDstMember, pAllocStep, pObject)           _ELst_ObjectAddA(&(pDstStruct->pDstMember), &(pDstStruct->pDstMember##_Count), &(pDstStruct->pDstMember##_CountAllocated), pAllocStep, pObject)
	#define ELst_ObjectAddA_om(pDstObject,pDstMember, pAllocStep, pObject)                                      _ELst_ObjectAddA(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pObject)
	#define ELst_ObjectAddA_s_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet)                       pRet = _ELst_ObjectAddA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pObject)
	#define ELst_ObjectAddAChk_s_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet)                    pRet = _ELst_ObjectAddAChk(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pObject)

	#define ELst_ObjectInsertA_s_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet)                 pRet = _ELst_ObjectInsertA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pWhere, pObject)
	#define ELst_ObjectInsertAChk_s_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet)              pRet = _ELst_ObjectInsertAChk(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pAllocStep, pWhere, pObject)
	#define ELst_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject,  mIndex) mIndex = _ELst_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject)
	#define ELst_ObjectAddAChk_r(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject, pRet)  pRet = _ELst_ObjectAddAChk(pListPtr, pNPointers, pNAllocatedPointers, pAllocStep, pObject)
	#define ELst_ObjectAddAChk_om_r(pDstObject,pDstMember, pAllocStep, pObject, pRet)                           pRet = _ELst_ObjectAddAChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pObject)
	#define ELst_ObjectInsertAChk_om_r(pDstObject,pDstMember, pAllocStep, pWhere, pObject, pRet)                pRet = _ELst_ObjectInsertAChk(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pAllocStep, pWhere, pObject)

#endif	// EObjectMEMORY_DEBUG


#define ELst_ObjectRemove_om(pDstObject,pDstMember, pObject)                    ELst_ObjectRemove(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
#define ELst_ObjectRemove_om_r(pDstObject,pDstMember, pObject, pRet)     pRet = ELst_ObjectRemove(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), pObject)
#define ELst_ObjectRemove_om_s_r(pDstObject,pDstMember, pObject, pRet)   pRet = ELst_ObjectRemove(&(pDstObject->pDstMember.Items), &(pDstObject->pDstMember.Count), pObject)
#define ELst_ObjectRemoveA_om(pDstObject,pDstMember, pObject)                   ELst_ObjectRemoveA(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pObject)
#define ELst_ObjectRemoveA_om_r(pDstObject,pDstMember, pObject, pRet)    pRet = ELst_ObjectRemoveA(&(pDstObject->pDstMember), &(pDstObject->pDstMember##_Count), &(pDstObject->pDstMember##_CountAllocated), pObject)
#define ELst_ObjectRemoveA_s_om(pDstObject,pDstMember, pObject)                 ELst_ObjectRemoveA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pObject)
#define ELst_ObjectRemoveA_s_om_r(pDstObject,pDstMember, pObject, pRet)  pRet = ELst_ObjectRemoveA(&(pDstObject->pDstMember).Items, &(pDstObject->pDstMember).Count, &(pDstObject->pDstMember).CountAllocated, pObject)
#define ELst_ObjectRemoveA_s(pListPtr, pObject)                                 ELst_ObjectRemoveA(&(pListPtr).Items, &(pListPtr).Count, &(pListPtr).CountAllocated, pObject)



//========================================================
// Standard recursive constructor (like in C++)
// This version is for statically allocated Objects
//========================================================
#define EM_ObjectInitStatic(pType, pObject, pClass) do\
{\
	const void*          vClass = pClass;\
	const pType##Class*  lClasses[EMAX_CLASS_DEPTH];const pType##Class*  lClass = (pType##Class*)vClass;\
	pType*               lllObject = (pType*)(pObject);\
	int                  lN = 0;\
\
	EEntityCore_Init(lllObject, TRUE);\
	lllObject->Class = (pType##Class*)lClass;\
	lllObject->BinResources = NULL;\
\
	_EM_ObjectMemDebugAdd(lllObject, Static);\
	_EM_ObjectPrint(lllObject, EMemDbgSTATIC_OBJECT_INIT);\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order  */\
\
	while(lClass)\
	{\
		lClasses[lN] = lClass;\
		lClass = lClass->SuperClass;\
		lN++;\
	}\
\
/*printf("%s() Class hierarchy depth: %d\n", __FUNCTION__, lN);fflush(stdout);\
	int  lLMaxIndent = lN;*/\
\
\
/* Call constructors  */\
\
	int  lI = lN;do\
	{\
		lClass = lClasses[lI - 1];\
		if(lClass->Init) lClass->Init(lllObject);\
\
/*	{\
			char  lLIndentStr[EMAX_CLASS_DEPTH + 2] = "";\
\
			memset(lLIndentStr, ' ', EMAX_CLASS_DEPTH + 2);lLIndentStr[lLMaxIndent - lI] = 0;\
			printf("%s <%s> %p\n", lLIndentStr, lClasses[lI - 1]->Name, pObject);fflush(stdout);\
		}\
*/\
\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);*/\
} while(0)

//========================================================================================================================
// Standard recursive constructor (like in C++)
// This version is for statically allocated Objects that are a memeber of another object. It makes the assignment tp
// that location, and updates reference counting / tracking, so the object can be freed with E_Delete() as usual
//========================================================================================================================
#define EM_ObjectInitStaticAssignToMember(pType,  pObject,pMember, pClass) do\
{\
	const void*          vClass = pClass;\
	const pType##Class*  lClasses[EMAX_CLASS_DEPTH];const pType##Class*  lClass = (pType##Class*)vClass;\
	pType*               lllObject = (pType*)(&(pObject)->pMember);\
	int                  lN = 0;\
\
	EEntityCore_Init(lllObject, TRUE);\
	lllObject->Class = (pType##Class*)lClass;\
	lllObject->BinResources = NULL;\
\
	_EM_ObjectMemDebugAdd(lllObject, Static);\
	_EM_ObjectPrint(lllObject, EMemDbgSTATIC_OBJECT_INIT);\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order  */\
\
	while(lClass)\
	{\
		lClasses[lN] = lClass;\
		lClass = lClass->SuperClass;\
		lN++;\
	}\
\
/*printf("%s() Class hierarchy depth: %d\n", __FUNCTION__, lN);fflush(stdout);\
	int  lLMaxIndent = lN;*/\
\
\
/* Call constructors  */\
\
	int  lI = lN;do\
	{\
		lClass = lClasses[lI - 1];\
		if(lClass->Init) lClass->Init(lllObject);\
\
/*	{\
			char  lLIndentStr[EMAX_CLASS_DEPTH + 2] = "";\
\
			memset(lLIndentStr, ' ', EMAX_CLASS_DEPTH + 2);lLIndentStr[lLMaxIndent - lI] = 0;\
			printf("%s <%s> %p\n", lLIndentStr, lClasses[lI - 1]->Name, lllObject);fflush(stdout);\
		}\
*/\
\
	} while(--lI);\
\
	_EM_ReferenceAdd(lllObject, lllObject, pObject->pMember,  pObject,#pMember,NULL);\
	lllObject->RefCnt+=1;\
/*printf("\n");fflush(stdout);*/\
} while(0)


//========================================================
// Standard recursive constructor (like in C++)
// This version is for dynamically allocated Objects
//========================================================
#define EM_ObjectInit(pType, pObject, pClass) do\
{\
	const void*          vClass = pClass;\
	const pType##Class*  lClasses[EMAX_CLASS_DEPTH];const pType##Class*  lClass = (pType##Class*)vClass;\
	pType*               lllObject = (pType*)(pObject);\
	int                  lN = 0;\
\
	EEntityCore_Init(lllObject, FALSE);\
	lllObject->Class = (pType##Class*)lClass;\
	lllObject->BinResources = NULL;\
\
	_EM_ObjectMemDebugAdd(lllObject,);\
	_EM_ObjectPrint(lllObject, EMemDbgOBJECT_INIT);\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order  */\
\
	while(lClass)\
	{\
		lClasses[lN] = lClass;\
		lClass = lClass->SuperClass;\
		lN++;\
	}\
\
\
/* Call constructors  */\
\
	int  lI = lN;\
	do\
	{\
		lClass = lClasses[lI - 1];\
		if(lClass->Init) lClass->Init(lllObject);\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);  */\
} while(0)


//================================================================
// Recursive constructor for Component Objects.
// This version is for dynamically allocated Objects.
//================================================================
#define EM_ObjectComponentInit(pType,  pObject, pComponent,  pClass) do\
{\
	const void*                   vClass = pClass;\
	const pType##ComponentClass*  lClasses[EMAX_CLASS_DEPTH];const pType##ComponentClass*  lClass = (pType##ComponentClass*)vClass;\
	pType##Component*             lComponent = (pType##Component*)(pComponent);\
	pType*                        lObject = (pType*)(pObject);\
\
	EEntityCore_Init(lComponent, FALSE);\
	lComponent->BinResources = NULL;\
\
	lComponent->Class = (pType##ComponentClass*)lClass;\
	lComponent->InternalFlags = lClass->InternalFlags;\
	lComponent->Flags = EComponentRESPOND_TO_INPUT_CHANGE;\
\
	lComponent->AttributeChangeCount = lComponent->InputChangeCount = 0;\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order  */\
\
	int  lN = 0;\
	while(lClass)\
	{\
		lClasses[lN] = lClass;\
		lClass = lClass->SuperClass;\
		lN++;\
	}\
\
/* Call constructors  */\
\
	int  lI = lN;\
	do\
	{\
		const pType##ComponentClass*  lTClass = lClasses[lI - 1];\
		if(lTClass->Init) lTClass->Init(lObject, lComponent);\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);  */\
\
	_EM_ObjectMemDebugAdd(lComponent,);\
	_EM_ObjectPrint(lComponent, EMemDbgOBJECT_INIT);\
} while(0)


//================================================================
// Recursive constructor for Component Objects.
// This version is for statically allocated Objects.
//================================================================
#define EM_ObjectComponentInitStatic(pType,  pObject, pComponent,  pClass) do\
{\
	const void*                   vClass = pClass;\
	const pType##ComponentClass*  lClasses[EMAX_CLASS_DEPTH];const pType##ComponentClass*  lClass = (pType##ComponentClass*)vClass;\
	pType##Component*             lComponent = (pType##Component*)(pComponent);\
	pType*                        lObject = (pType*)(pObject);\
\
	EEntityCore_Init(lComponent, TRUE);\
	lComponent->BinResources = NULL;\
\
	lComponent->Class = (pType##ComponentClass*)lClass;\
	lComponent->InternalFlags = EComponentDEFAULT;\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order  */\
\
	int  lN = 0;\
	while(lClass)\
	{\
		lClasses[lN] = lClass;\
		lClass = lClass->SuperClass;\
		lN++;\
	}\
\
/* Call constructors  */\
\
	int  lI = lN;\
	do\
	{\
		const pType##ComponentClass*  lTClass = lClasses[lI - 1];\
		if(lTClass->Init) lTClass->Init(lObject, lComponent);\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);  */\
\
	_EM_ObjectPrint(lComponent, EMemDbgOBJECT_INIT);\
} while(0)


//================================================================
// Recursive copy-constructor with option flags
//================================================================
#define EM_ObjectCopyTF(pType, pClass, pSrcObject, pDstObject, pFlags, pScene) do\
{\
	const pType##Class*  lClasses[EMAX_CLASS_DEPTH];\
	const pType##Class*  lClass = pClass;\
	const E3dObject*     lSrcObject = (E3dObject*)(pSrcObject);pType*  lDstObject = (pType*)(pDstObject);\
\
	EEntityCore_Init(lDstObject, FALSE);\
	if((pFlags & ECopyNAME) && lSrcObject->Name) EObject_SetName(lDstObject, EStrDup(lSrcObject->Name), FALSE);\
	lDstObject->Class = (pType##Class*)lClass;\
	lDstObject->BinResources = NULL;\
\
	_EM_ObjectMemDebugAdd(lDstObject,);\
	_EM_ObjectPrint(lDstObject, EMemDbgOBJECT_INIT);\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order */\
\
	int  lN = 0;\
	{\
		const pType##Class*  lTClass = lClass;while(lTClass)\
		{\
			lClasses[lN] = lTClass;\
			lTClass = lTClass->SuperClass;\
			lN++;\
		}\
	}\
\
/* Call copy-constructors (fall back to constructor if no copy-constructor is defined) */\
	int  lI = lN;\
	do\
	{\
		const pType##Class*  lTClass = lClasses[lI - 1];\
		if(lTClass->CopyWithFlags) lTClass->CopyWithFlags(lSrcObject, lDstObject, pFlags, pScene);\
		else if(lTClass->Copy) lTClass->Copy(lSrcObject, lDstObject);\
		else if(lTClass->Init) lTClass->Init(lDstObject);\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);*/\
} while(0)



//========================================================
// Standard recursive copy-constructor (like in C++)
//========================================================
#define EM_ObjectCopyC(pClass, pSrcObject, pDstObject) do\
{\
	const EObjectClass*  lClasses[EMAX_CLASS_DEPTH];\
	const EObjectClass*  lClass = pClass;\
	EObject*             lDstObject = pDstObject;\
\
	EEntityCore_Init(lDstObject, FALSE);\
	if(pSrcObject->Name)\
	{\
		const EBool  lNameStatic = pSrcObject->NameStatic;\
		if(lNameStatic) EObject_SetName(lDstObject, pSrcObject->Name, TRUE);\
		else EObject_SetName(lDstObject, EStrDup(pSrcObject->Name), FALSE);\
		lDstObject->NameStatic = lNameStatic;\
	}\
	lDstObject->Class = (EObjectClass*)lClass;\
	lDstObject->BinResources = NULL;\
\
	_EM_ObjectMemDebugAdd(lDstObject,);\
	_EM_ObjectPrint(lDstObject, EMemDbgOBJECT_INIT);\
\
/* Collect classes, so we can call constructors in superclass-to-subclass order */\
\
	int  lN = 0;\
	{\
		const EObjectClass*  lTClass = lClass;while(lTClass)\
		{\
			lClasses[lN] = lTClass;\
			lTClass = lTClass->SuperClass;\
			lN++;\
		}\
	}\
\
\
/* Call copy-constructors (fall back to constructor if no copy-constructor is defined)  */\
	int  lI = lN;\
	do\
	{\
		const EObjectClass*  lTClass = lClasses[lI - 1];\
		if(lTClass->Copy) lTClass->Copy(pSrcObject, lDstObject);\
		else if(lTClass->Init) lTClass->Init(lDstObject);\
	} while(--lI);\
\
/*printf("\n");fflush(stdout);*/\
} while(0)


#define E_CopyAssign(pOriginal, pNew) do\
{\
	const EObject*  lOriginal = (EObject*)pOriginal;if(lOriginal)\
	{\
		const EObjectClass*  llClass = lOriginal->Class;\
		EObject*             lNew = EMalloc(llClass->StructSize);if(lNew)\
		{\
/* Call copy-constructors if any  */\
			EM_ObjectCopyC(llClass, lOriginal, lNew);\
		}\
		E_Assign(lNew, pNew);\
	}\
} while(0)


//================================================================================
// Create a new Object
//
// pResult    The variable to put the result into
//
// Description
//  Allocates memory for a new Object and initializes it.
//
// See also
//  EClass.h/E_Delete
//================================================================================
#define E_NewNT(pResult) do\
{\
	typeof(pResult)  lObject;ENew(lObject);if(lObject)\
	{\
		EM_ObjectInit(EObject, lObject, __typeof__(*pResult)##_class);\
	}\
	pResult = lObject;\
} while(0)


//================================================================================
// Create a new Object
//
//  pType      The type of the Object. For example E3dMaterial
//  pResult    The variable to put the result into
//
// Description
//  Allocates memory for a new Object and initializes it.
//
// See also
//  EClass.h/E_Delete
//================================================================================
#define E_New(pType, pResult) do\
{\
	pType*  lObject;ENew(lObject);if(lObject)\
	{\
		EM_ObjectInit(EObject, lObject, pType##_class);\
	}\
	pResult = lObject;\
} while(0)


//========================================================================================
// Create a new Object
//
//  pType      The type of the Object. For example E3dMaterial
//  pResult    The variable to put the result into
//  pName      The name of the new Object
//
// Description
//  Allocates memory for a new Object and initializes it, then sets the Object's name.
//  The name is duplicated via EStrDup(), so the original may be freed by the caller.
//
// See also
//  EClass.h/E_Delete
//========================================================================================
#define E_NewNamed(pType, pName,  pResult) do\
{\
	const char*  lName = pName;\
	pType*  lObject;ENew(lObject);if(lObject)\
	{\
		EM_ObjectInit(EObject, lObject, pType##_class);\
		if(lName) EObject_SetName(lObject, EStrDup(lName), FALSE);\
	}\
	pResult = lObject;\
} while(0)

//========================================================================================
// Create a new Object
//
//  pClass     The class of the Object. For example E3dMaterial_class
//  pName      The name of the new Object
//  pResult    The variable to put the result into
//
// Description
//  Allocates memory for a new Object and initializes it, then sets the Object's name.
//  The name is duplicated via EStrDup(), so the original may be freed by the caller.
//
// See also
//  EClass.h/E_Delete
//========================================================================================
#define E_NewNamedC(pClass, pName,  pResult) do\
{\
	const char*  lName = pName;\
	typeof(pResult)  lObject;EMallocT(typeof(pResult), (pClass)->StructSize, lObject);if(lObject)\
	{\
		EM_ObjectInit(EObject, lObject, pClass);\
		if(lName) EObject_SetName(lObject, EStrDup(lName), FALSE);\
	}\
	pResult = lObject;\
} while(0)

//========================================================================================
// Create a new Object and assign it to the given target
//
//  pType      The type of the Object. For example E3dMaterial
//  pName      The name of the new Object
//  pResult    The variable to put the result into
//
// Description
//  Allocates memory for a new Object and initializes it, then sets the Object's name.
//  The name is duplicated via EStrDup(), so the original may be freed by the caller.
//
// See also
//  EClass.h/E_Delete
//========================================================================================
#define E_NewNamedAssign(pType, pName,  pResult) do\
{\
	const char*  lName = pName;\
	pType*  lObject;ENew(lObject);if(lObject)\
	{\
		EM_ObjectInit(EObject, lObject, pType##_class);\
		if(lName) EObject_SetName(lObject, EStrDup(lName), FALSE);\
	}\
	E_Assign(lObject, pResult);\
} while(0)

//========================================================================================
// Create a new Object and assign it to the given target
//
//  pClass     The class of the Object. For example E3dMaterial_class
//  pName      The name of the new Object
//  pResult    The variable to put the result into
//
// Description
//  Allocates memory for a new Object and initializes it, then sets the Object's name.
//  The name is duplicated via EStrDup(), so the original may be freed by the caller.
//
// See also
//  EClass.h/E_Delete
//========================================================================================
#define E_NewNamedAssignC(pClass, pName,  pResult) do\
{\
	const char*  lName = pName;\
	typeof(pResult)  lNObject;EMallocT(typeof(pResult), (pClass)->StructSize, lNObject);if(lNObject)\
	{\
		EM_ObjectInit(EObject, lNObject, pClass);\
		if(lName) EObject_SetName(lNObject, EStrDup(lName), FALSE);\
	}\
	E_Assign(lNObject, pResult);\
} while(0)


//================================================================================
// Create a new Object and assign it to pResult
//
// pType      The type of the Object. For example E3dMaterial
// pResult    The variable to put the result
//
// Description
//  Allocates memory for a new Object and initializes it, then assigns it to pResult with reference-tracking.
//
// See also
//  EClass.h/E_Delete
//================================================================================
#define E_NewAssign(pType, pResult) do\
{\
	pType*  pObject;ENew(pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pType##_class);\
	}\
	E_Assign(pObject, pResult);\
} while(0)


#define E_NewAssignNoChkNoFree(pType, pResult) do\
{\
	pType*  pObject;ENew(pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pType##_class);\
	}\
	E_AssignNoChkNoFree(pObject, pResult);\
} while(0)


#define E_NewAssignToMember(pType,  pResult,pMember) do\
{\
	pType*  pObject;ENew(pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pType##_class);\
	}\
	E_AssignToMember(pObject,  pResult,pMember);\
} while(0)


//================================================================================
// Declare a temporary variable and assign an Object to it
//
// pType      The type of the Object. For example E3dMaterial
// pResult    The variable to put the result
//
// Description
//  Declares a variable pResult and assigns object pSrc to it.
//
// See also
//  EClass.h/E_Delete
//================================================================================
#define E_Object(pType, pSrc, pResult)  pType*  pResult;E_AssignNoChkNoFree(pSrc, pResult)


#define E_NewC(pClass, pResult) do\
{\
	typeof(pResult)  pObject;EMallocT(typeof(pResult), (pClass)->StructSize, pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pClass);\
	}\
	pResult = pObject;\
} while(0)

#define E_NewCAssign(pClass, pResult) do\
{\
/*printf("%s() %s:%d  (pClass)->StructSize %d\n", __FUNCTION__, __FILE__, __LINE__, (pClass)->StructSize);fflush(stdout);*/\
	typeof(pResult)  pObject;EMallocT(typeof(pResult), (pClass)->StructSize, pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pClass);\
	}\
	E_Assign(pObject, pResult);\
} while(0)


#define E_NewCAssignNoChkNoFree(pClass, pResult) do\
{\
/*printf("%s() %s:%d  (pClass)->StructSize %d\n", __FUNCTION__, __FILE__, __LINE__, (pClass)->StructSize);fflush(stdout);*/\
	typeof(pResult)  pObject;EMallocT(typeof(pResult), (pClass)->StructSize, pObject);if(pObject)\
	{\
		EM_ObjectInit(EObject, pObject, pClass);\
	}\
	E_AssignNoChkNoFree(pObject, pResult);\
} while(0)


//================================================================================================================
// Recursive destructor template function
//
// Our OO framework is more powerful than that of C++,Java etc.
// Destructor functions are called in subclass-to-superclass order, as usual, however the destructor functions
// can cancel the destruction process at any level.
// If a destructor function returns a value other than E_SUCCESS, the destruction process will terminate at that point,
// and the object will be essentialy turned into an object of the lowest derived, non-destructed class.
// This allows for partially destructed Objects and runtime Object reclassification, which is essential for efficient, runtime-updateable code.
// Destructor functions can completely cancel the destruction process, by returning other than E_SUCCESS, immediately, from the destructor of lowest derived class.
// This allows for supporting efficient and robust reference counting / tracking and garbage collection, especially when objects are connected
// in complex graph structures, cross-referenced etc.
// In that case, reference tracking could get very complex and it should be left to the class implementation.
//================================================================================================================
#define EM_ObjectFreeAllowPartial(pType, pObject, pResult) do\
{\
	pType*  lllObject = (pType*)(pObject);\
	int     lResult = E_SUCCESS;\
\
	if(lllObject->Class)\
	{\
		pType##Class*  lClass = lllObject->Class;\
\
/* Call destructors in subclass-to-superclass order	*/\
		while(lClass)\
		{\
			if(lClass->Free)\
			{\
				const int  lTResult = lClass->Free(lllObject);if(lTResult != E_SUCCESS)\
				{\
					lResult = lTResult;\
					break;\
				}\
			}\
\
			lClass = lClass->SuperClass;\
		}\
	}\
\
	if(lResult == E_SUCCESS)\
	{\
		EFreeChkClr(lllObject->BinResources);\
		_EM_ObjectMemDebugDel(lllObject);\
		EEntityCore_Free(lllObject);  /* Free the name last, so if something goes wrong, we can identify the Object while debugging */\
	}\
	pResult = lResult;\
} while(0)


//========================================================================================================
// Recursive destructor template function internal version for EMemDbg_Clear
// - No tracking via. _E_Objects
//
// This OO framework allows for partially destructed Objects and runtime Object reclassification.
// Destructor functions are called in subclass-to-superclass order, as usual.
// However, if a destructor function returns the enum value E_DO_NOT_FREE, the destruction process
// will terminate at that point and the object will be essentialy turned into an object of the
// lowest derived, non-destructed class.
// This feature is essential for efficient runtime-updateable code.
//=========================================================================================================
#define _EM_ObjectFreeAllowPartial(pType, pObject) do\
{\
	pType*  lllObject = (pType*)(pObject);\
	int     lStatus = 0;\
\
	if(!lllObject->Static && lllObject->Class)\
	{\
		pType##Class*  lClass = lllObject->Class;\
\
/* Call destructors in subclass-to-superclass order	*/\
\
		while(lClass)\
		{\
			if(lClass->Free)\
			{\
				const int  lResult = lClass->Free(lllObject);if(lResult != E_SUCCESS)\
				{\
					lStatus = lResult;\
					break;\
				}\
			}\
\
			lClass = lClass->SuperClass;\
		}\
	}\
\
	if(lStatus == 0)\
	{\
		EFreeChk(lllObject->BinResources);\
		EEntityCore_Free(lllObject);  /* Free the name last, so if something goes wrong, we can identify the Object while debugging */\
	}\
} while(0)


typedef struct ECoreClass_S         ECoreClass;
typedef struct ECoreClass_S*        ECoreClassPtr;
typedef const struct ECoreClass_S*  EConstCoreClassPtr;


#define EClassABSTRACT                0x01    // Abstract class. Not to be instantiated
#define EClassRESOURCES_STATIC        0x02    // Resources were statically allocated (i.e. do not free them)
#define EClassOBJECT_ACTIVE_INACTIVE  0x04    // Add an "Active" ToggleButton to class drop-down headers


//
// Core meta class with user-defined type, Name and Resources
// It does not define a constructor and a destructor, so the inheritor can define those with specific function signatures.
//
#define ECoreClassCore(pType)\
	char*          Name;\
	EIndex         StructSize;\
	pType##Class*  SuperClass;\
	EList_s(, EResource, Resources);         /* Resources for this class. .Items != NULL, but Count = 0 means a 0-terminated list */\
	EList_s(, EResource, AllResources);      /* Resources for this class and all of its superclasses. Dynamically allocated - must be freed! */\
	uint16_t       ClassBase : 1,            /* BaseClass (it has standard constructor/destructor etc.) */\
	               ClassDynamic : 1,         /* Dynamically allocated class */\
	               ClassActive : 1,          /* The class is active (e.g. the plugin that registered it is loaded */\
	               ClassRegistered : 1,      /* Class was added to a global list (e.g. Xe_Classes) */\
	               ClassTrackInstances : 1;  /* Keep Objects list up-to-date  */\
	uint16_t       ClassFlags;               /* EClassABSTRACT etc. */\
	EListA_s(, EObjectPtr, Instances)        /* All instances of Objects of this class	*/


typedef struct ECoreObject_S   ECoreObject;

typedef struct EObject_S       EObject;
typedef struct EObject_S*      EObjectPtr;
EListA_t(EObjectPtr);
typedef struct EObjectClass_S  EObjectClass;

struct ECoreClass_S
{
	ECoreClassCore(ECore);
};


#define ECoreClass_Deactivate(pClass, pFreeResources) do\
{\
	ECoreClass*  lClass = (ECoreClass*)(pClass);\
	lClass->ClassActive = FALSE;\
	if(pFreeResources)\
	{\
		if(lClass->ClassFlags & EClassRESOURCES_STATIC) EList_Init_s(lClass->Resources);\
		else EResources_Free(&lClass->Resources, 0);\
	}\
	EList_FreeChk_s(lClass->AllResources);  /* This is rebuilt dynamically from the superclasses, etc. anyway */\
} while(0)


//
// A more advanced meta-class base, with instance-tracking capability.
// It also defines a standard constructor, copy-constructor and destructor.
// Note that the type of those methods depends on the sub-class, so EBaseClass is not defined as a typeded struct.
//
#define EBaseClassCore(pType)\
	ECoreClassCore(pType);\
	void  (*Init)(pType* PObject);\
	int   (*Copy)(const pType* POrig, pType* PNew);\
	int   (*Free)(pType* PObject);\
	int   (*ClassFree)(pType##Class* PClass)

#define EBaseClass_Init(pDescriptor, pFlags, pTrackInstances) do\
{\
	ECoreClass_Init((ECoreClass*)(pDescriptor), (ECoreClass*)LClass, pFlags, pTrackInstances);\
	LClass->ClassActive = TRUE;\
	LClass->ClassBase = TRUE;\
	LClass->ClassFlags |= ((pFlags) & EClassRESOURCES_STATIC);\
\
	LClass->Init = pDescriptor->Init;\
	LClass->Free = pDescriptor->Free;\
	LClass->Copy = pDescriptor->Copy;\
\
	LClass->ClassFree = pDescriptor->ClassFree;\
} while(0)

#define EBaseClass_InitNew(pDescriptor, pFlags, pTrackInstances) do\
{\
	ECoreClass_InitNew((ECoreClass*)(pDescriptor), (ECoreClass*)LClass, pFlags, pTrackInstances);\
	LClass->ClassActive = TRUE;\
	LClass->ClassBase = TRUE;\
	LClass->ClassFlags |= ((pFlags) & EClassRESOURCES_STATIC);\
\
	LClass->Init = pDescriptor->Init;\
	LClass->Free = pDescriptor->Free;\
	LClass->Copy = pDescriptor->Copy;\
\
	LClass->ClassFree = pDescriptor->ClassFree;\
} while(0)

#define EBaseClass_InitInactiveNew(pName, pTrackInstances) do\
{\
	ECoreClass_InitInactiveNew(pName, (ECoreClass*)LClass, pTrackInstances);\
	LClass->ClassBase = TRUE;\
\
	LClass->Init = NULL;\
	LClass->Free = NULL;\
	LClass->Copy = NULL;\
\
	LClass->ClassFree = NULL;\
} while(0)

#define EBaseClass_Deactivate(pClass, pFreeResources) do\
{\
	ECoreClass_Deactivate(pClass, pFreeResources);\
\
/* These use the macro param, as EBaseClass is not defined as a type struct */\
/* because the Init()/Free()/Copy() members' type depends on the subclass */\
	(pClass)->Init = NULL;\
	(pClass)->Free = NULL;\
	(pClass)->Copy = NULL;\
\
	(pClass)->ClassFree = NULL;\
} while(0)


#if EObjectMEMORY_DEBUG

//========================================================
// Add reference
//========================================================
#define _EM_ReferenceAdd(pSrc, pReferenceAddress, pAddressName,  pReferringObject,pReferringMemberName,pResourceName) do\
{\
	EObjectMemEntry*  lEntry;_EObject_Find(pSrc, &lEntry);if(lEntry)\
	{\
		_M_ObjectEntryCheckRef(pSrc, lEntry);\
\
		EObjectReference*  lReference = EList_StructAddA(lEntry->References, 16);\
\
		lReference->Address = pReferenceAddress;\
		lReference->AddressString = (char*)(#pAddressName);\
		lReference->ReferringObject = (ECoreObject*)(pReferringObject);lReference->ReferringMemberName = pReferringMemberName;lReference->ResourceName = pResourceName;\
\
		ECallerInfo*  lCaller = &lReference->Caller;\
		lCaller->FileName = __FILE__;\
		lCaller->Function = __FUNCTION__;\
		lCaller->Line = __LINE__;\
		lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
	}\
} while(0)


#define _M_ReferenceDel(pObject, pReferenceAddress) do\
{\
	EObjectMemEntry*  lEntry;const int  lResult = _EObject_Find(pObject, &lEntry);if(lEntry)\
	{\
		_M_ObjectEntryCheckRef(pObject, lEntry);\
		if(_E_ReferenceDel(lEntry, pReferenceAddress) == E_NOT_FOUND)\
		{\
			if(EMemDbg_BadRefResponse & E_PRINT)\
			{\
				printf("%s() %s:%d _M_ReferenceDel()  %sAttempting to release Object %p:{%s}:%s from address %p, but the Object was not assigned to this address with E_Assign*()%s.\n", __FUNCTION__, __FILE__, __LINE__, ECodeYellow, pObject, pObject->Class->Name, pObject->Name ? pObject->Name : "-", pReferenceAddress, ECodeNormal);fflush(stdout);\
				const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;_EObject_PrintReferences(lEntry, lResult == E_FREED, lExecutableNameLen, TRUE);\
			}\
			if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
		}\
	}\
} while(0)


#define _EM_Del(pObject) do\
{\
	EObjectMemEntry*  lEntry;_EObject_Find(pObject, &lEntry);if(lEntry)\
	{\
		_M_ObjectEntryCheckRef(pObject, lEntry);\
		{\
			if(pObject->RefCnt<=0)\
			{\
				ECallerInfo*  lCaller = &lEntry->Freeing;\
				lCaller->FileName = __FILE__;\
				lCaller->Function = __FUNCTION__;\
				lCaller->Line = __LINE__;\
				lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
			}\
			_E_Delete(pObject);\
		}\
	}\
	else\
	{\
		if(EMemDbg_BadRefResponse & E_PRINT) { printf("%s() %s:%d  %sAttempting to delete non-object %p%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeRed, pObject, ECodeNormal);fflush(stdout); }\
		if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
	}\
} while(0)


#define _EM_Delete(pObject, pReferenceAddress) do\
{\
	ECoreObject*  lObject = (ECoreObject*)(pObject);\
	EObjectMemEntry*  lEntry;const int  lResult = _EObject_Find(lObject, &lEntry);if(lEntry)\
	{\
		_M_ObjectEntryCheckRef(lObject, lEntry);\
		if(_E_ReferenceDel(lEntry, pReferenceAddress) == E_NOT_FOUND)\
		{\
			if(EMemDbg_BadRefResponse & E_PRINT)\
			{\
				printf("  _EM_Delete()  Object %s%p%s:{%s}:%s %sAttempting to release from address %p, but it was not assigned to this address with E_Assign*()%s.\n",  ECodeCyan, lObject, ECodeNormal,  lObject->Class->Name, lObject->Name ? lObject->Name : "-",  ECodeYellow, pReferenceAddress, ECodeNormal);fflush(stdout);\
				const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;\
				void*  lCallStack[EMAX_CALLSTACK_DEPTH];const EIndex lCallStackDepth = _EM_backtrace(lCallStack);\
				if(lCallStackDepth > 0) { _E_CallStackPrint(lCallStack, lCallStackDepth, 0, lExecutableNameLen); }\
				_EObject_PrintReferences(lEntry, lResult == E_FREED, lExecutableNameLen, TRUE);\
			}\
			if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
		}\
		else\
		{\
			if(lObject->RefCnt<=0)\
			{\
				ECallerInfo*  lCaller = &lEntry->Freeing;\
				lCaller->FileName = __FILE__;\
				lCaller->Function = __FUNCTION__;\
				lCaller->Line = __LINE__;\
				lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
			}\
			_E_Delete(lObject);\
		}\
	}\
	else\
	{\
		if(EMemDbg_BadRefResponse & E_PRINT) { printf("%s() %s:%d  %sAttempting to delete non-object %p%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeRed, lObject, ECodeNormal);fflush(stdout); }\
		if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
	}\
} while(0)


#define _EM_DeleteNoRef(pObject, pReferenceAddress) do\
{\
	EObjectMemEntry*  lEntry;const int  lResult = _EObject_Find(pObject, &lEntry);(void)lResult;if(lEntry)\
	{\
		_E_Delete(pObject);\
	}\
	else\
	{\
		if(EMemDbg_BadRefResponse & E_PRINT) { printf("%s() %s:%d  %sAttempting to delete non-object %p%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeRed, pObject, ECodeNormal);fflush(stdout); }\
		if(EMemDbg_BadRefResponse & E_ASSERT) assert(0);\
	}\
} while(0)


#define _EM_DeleteCore(pObject, pReferenceAddress) do\
{\
	EObjectMemEntry*  lEntry;_EObject_Find(pObject, &lEntry);if(lEntry)\
	{\
		_M_ObjectEntryCheckRef(pObject, lEntry);\
		_E_ReferenceDel(lEntry, pReferenceAddress);\
		if(pObject->RefCnt<=0)\
		{\
			ECallerInfo*  lCaller = &lEntry->Freeing;\
			lCaller->FileName = __FILE__;\
			lCaller->Function = __FUNCTION__;\
			lCaller->Line = __LINE__;\
			lCaller->CallStackDepth = _EM_backtrace(lCaller->CallStack);\
		}\
	}\
} while(0)

#else

#define	_EM_ReferenceAdd(pSrc, pReferenceAddress, pAddressName,  pReferringObject,pReferringMember, pResourceName)
#define	_M_ReferenceDel(lEntry, pReferenceAddress)
#define _EM_DeleteCore(pObject, pReferenceAddress)

#define _EM_Del(pObject) do\
{\
	_E_Del(pObject);\
} while(0)

#define _EM_Delete(pObject, pReferenceAddress) do\
{\
	_E_Delete(pObject);\
} while(0)

#define _EM_DeleteNoRef(pObject, pReferenceAddress) do\
{\
	_E_Delete(pObject);\
} while(0)

#endif	//	EObjectMEMORY_DEBUG


//
// Delete object without un-assinging
//
#define E_Del(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);\
\
	_EM_Del(lllObject);\
	pObject = NULL;\
} while(0)


//================================================================================================
// Un-assign an Object from a variable, memory location etc. and delete it if it's not used any more
//
// Description
//  This function:<BR>
//  - Translates the argument to an address (via the '&' operator) and releases the given Object from that referrer.
//  - Sets the referrer to NULL, so the application code doesn't have to (this helps avoiding "dangling pointers, whether it's in a struct or a local variable").
//  - Updates reference-tracking information used by the optional garbage-collector (in debug mode, when EObjectMEMORY_DEBUG is defined).<BR>
//  - If the Object is not referenced anywhere else, it gets deleted / freed.
//
//  Example:
// <PRE> {
//   EObject*  MyObjects[50];
// ...
//   E_Delete(MyObjects[42]);
// }</PRE>
//
// See also
//  E_Assign, E_Release, EClass.c/EMemDbg_ObjectsPrint
//================================================================================================
#define E_Delete(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);\
\
	pObject = NULL;  /* Clear the reference first for better thread-safety */\
	_EM_Delete(lllObject, &(pObject));\
} while(0)


//========================================================================
// Use these for unassigned objects. E.g. temporary / local variables
// where it's not worth dealing with reference counting / tracking
//========================================================================
#define E_DeleteNoRef(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);\
\
	pObject = NULL;  /* Clear the reference first for better thread-safety */\
	_EM_DeleteNoRef(lllObject, &(pObject));\
} while(0)

#define E_DeleteChkNoRef(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);if(lllObject)\
	{\
		pObject = NULL;  /* Clear the reference first for better thread-safety */\
		_EM_DeleteNoRef(lllObject, &(pObject));\
	}\
} while(0)


#define E_DeleteStatic(pObject) do\
{\
	EObject*  lllObject = (EObject*)&(pObject);\
\
	_EM_Delete(lllObject, &(pObject));\
} while(0)


#define E_DeleteChk(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);if(lllObject)\
	{\
		pObject = NULL;  /* Clear the reference first for better thread-safety */\
		_EM_Delete(lllObject, &(pObject));\
	}\
} while(0)


//================================================================================================
// Un-assign an Object from a variable, memory location etc.
//
// Description
//  Releases the given Object from a referring address and updates the referencing information used
//  by the optional garbage-collector (in debug mode, when EObjectMEMORY_DEBUG is defined).
//  Unlike E_Delete, it does not free (delete) the Object when it's not referenced any more.<BR>
//  This macro is normally used when a pointer to the Object is being moved (e.g. from an
//  old pointer array to a new one).<BR>
//  In this case, you release the Object from the old array and re-assign it to the new array.
//  If you called E_Delete and the old array was the only referrer, the Object would get
//  destructed, which is not what you would want.
//  Use this function only if necessary.
//
// See also
//  E_Assign, E_Delete, EClass.c/EMemDbg_ObjectsPrint
//================================================================================================
#define E_Release(pObject) do\
{\
	EObject*  lllObject = (EObject*)(pObject);if(lllObject)\
	{\
		pObject = NULL;\
		_M_ReferenceDel(lllObject, &(pObject));\
		if(lllObject->RefCnt>0) lllObject->RefCnt-=1;\
	}\
} while(0)


//================================================================================================
// Assign Object to a variable, memory location etc.
//
// Arguments
//  pObject   The source Object
//  pDst      The destination : must NOT be a function call or contain an increment/decrement operator (e.g. LC++)
//
// Description
//  Assigns the given Object to the destination and updates the referencing information used by
//  the optional garbage-collector (in debug mode, when EObjectMEMORY_DEBUG is defined).
//  pDst must be a value for which an address is available (via the & operator).<BR>
//<BR>
//  By using this macro (instead of just assigning via the '=' operator) you will have a powerful
//  memory reference-tracking facility available for debugging.<BR>
//  This system can tell what Objects are created from where (source file + line number).
//  It can even tell where a given Object is being referenced (source files + line numbers).
//  This makes debugging most memory issues a snap.<BR>
//  Because this facility works at the level of reflective-Objects and the application still runs natively
//  (as opposed to when running under Valgrind), the output can be much more informative (it shows Object and Class names etc.)
//  and the runtime overhead is minimal.
//  There is no overhead when EObjectMEMORY_DEBUG is not defined (e.g. in release builds).<BR>
//  Using this facility for high-level, and Valgrind for low-level code verification can dramatically
//  improve code quality and stability.
//
// See also
//  E_Release, E_Delete, EClass.c/EMemDbg_ObjectsPrint
//================================================================================================
#define E_Assign(pObject, pDst) do\
{\
	typeof(pDst)  ltObject = (typeof(pDst))(pObject);	/* It is *imperative* that pObject is only referenced ONCE, because it may be a function call etc.	*/\
	EObject*      lllObject = (EObject*)(ltObject);\
	EObject*      lOldObject = (EObject*)(pDst);\
\
	if(lllObject != lOldObject)\
	{\
		if(lOldObject)\
		{\
			_EM_Delete(lOldObject, &(pDst));\
		}\
		pDst = ltObject;\
		if(lllObject)\
		{\
			_EM_ReferenceAdd(lllObject, &(pDst), pDst,  NULL,NULL,NULL);\
			lllObject->RefCnt+=1;\
		}\
	}\
} while(0)

#define E_Assign_p(pObject, pDst) do\
{\
	typeof(*pDst)  ltObject = (typeof(*pDst))(pObject);  /* It is *imperative* that pObject is only referenced ONCE, because it may be a function call etc.	*/\
	EObject*       lllObject = (EObject*)(ltObject);\
	EObject*       lOldObject = (EObject*)(*(pDst));\
\
	if(lllObject != lOldObject)\
	{\
		if(lOldObject)\
		{\
			_EM_Delete(lOldObject, pDst);\
		}\
		*pDst = ltObject;\
		if(lllObject)\
		{\
			_EM_ReferenceAdd(lllObject, pDst, pDst,  NULL,NULL,NULL);\
			lllObject->RefCnt+=1;\
		}\
	}\
} while(0)

/*
#define E_Assign(pObject, pDst) do\
{\
	typeof(pDst)   ltObject = (typeof(pDst))(pObject);  @* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.  @/\
	typeof(pDst)*  lDstP = (&pDst);                     @* It's imperative that pDst is only referenced ONCE, because it may be a function call etc.     @/\
	EObject*       lllObject = (EObject*)(ltObject);\
	EObject*       lDst = (EObject*)(*lDstP);\
\
	if(lllObject != lDst)\
	{\
		if(lDst)\
		{\
			_EM_Delete(lDst, lDstP);\
		}\
		*lDstP = ltObject;\
		if(lllObject)\
		{\
			_EM_ReferenceAdd(lllObject, lDstP, lDst,  NULL,NULL,NULL);\
			lllObject->RefCnt+=1;\
		}\
	}\
} while(0)
*/

#define E_AssignNoChkNoFree(pObject, pDst) do\
{\
	typeof(pDst)  ltObject = (typeof(pDst))(pObject);  /* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.  */\
	EObject*      lllObject = (EObject*)(ltObject);\
\
	pDst = ltObject;\
	if(lllObject)\
	{\
		_EM_ReferenceAdd(lllObject, &(pDst), pDst,  NULL,NULL,NULL);\
		lllObject->RefCnt+=1;\
	}\
} while(0)


//========================================================================================================
// Assign Object to a member of another Object
//
// Description
//  This is very useful for debugging because the reference tracker will be able to tell what Objects are
//  referencing other Objects (when EObjectMEMORY_DEBUG is enabled).
//  Using E_Assign will only track the raw memory addresses of Object references.
//========================================================================================================
#define E_AssignToMember(pObject,  pDstObject,pDstMember) do\
{\
	typeof(pDstObject->pDstMember)  ltObject = (typeof(pDstObject->pDstMember))(pObject);  /* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.	*/\
	EObject*                        lllObject = (EObject*)(ltObject);\
	EObject*                        lOldObject = (EObject*)(pDstObject->pDstMember);\
\
	if(lllObject != lOldObject)\
	{\
		if(lOldObject)\
		{\
			_EM_Delete(lOldObject, &(pDstObject->pDstMember));\
		}\
		pDstObject->pDstMember = ltObject;\
		if(lllObject)\
		{\
			_EM_ReferenceAdd(lllObject, &(pDstObject->pDstMember), pDstObject->pDstMember,  pDstObject,#pDstMember,NULL);\
			lllObject->RefCnt+=1;\
		}\
	}\
} while(0)



#define E_AssignToMemberNoChk(pObject,  pDstObject, pDstMember) do\
{\
	typeof(pDstObject->pDstMember)  ltObject = (typeof(pDstObject->pDstMember))(pObject);  /* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.  */\
	EObject*                        lllObject = (EObject*)(ltObject);\
	EObject*                        lOldObject = (EObject*)(pDstObject->pDstMember);\
\
	if(lOldObject)\
	{\
		_EM_Delete(lOldObject, &(pDstObject->pDstMember));\
	}\
	pDstObject->pDstMember = ltObject;\
	if(lllObject)\
	{\
		_EM_ReferenceAdd(lllObject, &(pDstObject->pDstMember), pDstObject->pDstMember,  pDstObject,#pDstMember,NULL);\
		lllObject->RefCnt+=1;\
	}\
} while(0)


#define E_AssignToMemberNoChkNoFree(pObject,  pDstObject,pDstMember) do\
{\
	typeof(pDstObject->pDstMember)  ltObject = (typeof(pDstObject->pDstMember))(pObject);  /* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.  */\
	EObject*                        lllObject = (EObject*)(ltObject);\
\
	pDstObject->pDstMember= ltObject;\
	if(lllObject)\
	{\
		_EM_ReferenceAdd(lllObject, &(pDstObject->pDstMember), pDstObject->pDstMember,  pDstObject,#pDstMember,NULL);\
		lllObject->RefCnt+=1;\
	}\
} while(0)


#define E_AssignToProxy(pObject, pDst,  pDstObject, pDstResourceName) do\
{\
	typeof(pDst)  ltObject = (typeof(pDst))(pObject);	/* It's imperative that pObject is only referenced ONCE, because it may be a function call etc.	*/\
	EObject*      lllObject = (EObject*)(ltObject);\
	EObject*      lOldObject = (EObject*)(pDst);\
\
	if(lllObject != lOldObject)\
	{\
		if(lOldObject)\
		{\
			_EM_Delete(lOldObject, &(pDst));\
		}\
		pDst = ltObject;\
		if(lllObject)\
		{\
			_EM_ReferenceAdd(lllObject, &(pDst), pDst,  pDstObject,pDstResourceName, pDstResourceName);\
			lllObject->RefCnt+=1;\
		}\
	}\
} while(0)


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


// For statically allocated arrays
//
#define	EMAX_CLASS_DEPTH       64

#ifndef XeInfoPanel_DEF
#define XeInfoPanel_DEF  1
typedef struct XeInfoPanel_S   XeInfoPanel;
typedef struct XeInfoPanel_S*  XeInfoPanelPtr;
EListA_t(XeInfoPanelPtr);
#endif

typedef void  (*ECoreObjectGUIFunc)(ECoreObject* PObject, XeInfoPanel* PPanel, void* PDrawer, const int PAction);


struct EObjectClass_S
{
	EBaseClassCore(EObject);
};


typedef struct
{
	void*        Address;        // Reference address (where the pointer to the Object is)
	char*        AddressString;  // Reference address as a string

// This allows collapsing reference chains for better readability of debugging output. For example:
// PolyGroup "A" is not freed because Mesh "B" (which isn't freed either) is referencing it. Also, Mesh is not freed because "B" Model "C" is referencing it.
// In this case, we know that the original "culprit" is the fact that Model "A" is not freed, so there's no need to display PolyGroup "A" and Mesh "B".
//
	ECoreObject*  ReferringObject;const char*  ReferringMemberName;const char*  ResourceName;  // ReferringMemberName and ResourceName may be different and one might be given, while the other not...

// Source code for this Reference.
//
	ECallerInfo  Caller;
} EObjectReference;

//------------------------------------------------------------------------------------------------
// Reflective Object base class template with reference-counting, name, resources etc.
// These Objects "know" what they are and what they can do. Information about their
// type (class name), member functions, memory layout (struct-size & Resources) etc. may
// be accessed and manipulated in runtime (full runtime reflection) via their "Class" member.
//
// This is a type-independent template to allow for multiple independent base classes.
//------------------------------------------------------------------------------------------------
#define EObjectCore(pType)\
	EEntityCore;\
	pType##Class*  Class;\
\
/* This field is used to save the values of Resources of objects into binary images ("serializing") for the deferred  */\
/* decoding of Resources. For example:                                                                                */\
/* When reading an Object from a file, if its Class is not registered and active, we can store the Resource values in */\
/* a binary format, so if an appropriate plugin is loaded later, we can decode the Resources and use this Object.     */\
/* Also, when a Class is deactivated (the plugin for a Class is unloaded), all Objects of this Class are "sliced"     */\
/* to the superclass.                                                                                                 */\
/* This would mean losing the values of Resources defined by this Class, however we can encode them here and restore  */\
/* them if/when the Class is reactivated. This works even if the re-registered class changed the memory layout of the */\
/* (class/struct) members.                                                                                            */\
/* The above allows for on-the-fly code updates to applications without losing content (e.g. shaders in a 3D scene).  */\
/* This kind of runtime flexibility is not present in the C++ OOP infrastructure, which is one of the                 */\
/* reasons we chose C99 for our object-oriented designs.                                                              */\
	uint8_t*       BinResources


#define	E_IsSubClass_p(pClass0, pClass1)        _E_IsSubClass((ECoreClass*)(pClass0), pClass1)
#define	E_IsSubClass(pClass0, pType)		        _E_IsSubClass((ECoreClass*)(pClass0), pType##_class)
#define	EObject_IsSubClass(pObject, pType)      _E_IsSubClass((ECoreClass*)(pObject->Class), pType##_class)
#define	EObject_IsSubClass_p(pObject, pClass1)  _E_IsSubClass((ECoreClass*)(pObject->Class), pClass1)

//
// Dynamic cast macro
// If pObject is not NULL and it is derived from pType, it returns a properly cast object, otherwise returns NULL
//
#define E_DynamicCast(pObject, pType)  (pObject) && EObject_IsSubClass(((ECoreObject*)(pObject)), pType) ? (pType*)(pObject) : NULL

#define E_DynamicCastC(pObject, pClass)  (pObject) && EObject_IsSubClass(((ECoreObject*)(pObject)), pType) ? (pType*)(pObject) : NULL

// The simplest base Object, with no default constructor and destructor
//
struct ECoreObject_S
{
	EObjectCore(ECore);
};


// Base Object, with default constructor and destructor
//
struct EObject_S
{
	EObjectCore(EObject);
};



// Used for storing EObject and its position in array (e.g. undo/redo)
//
typedef struct
{
	EObject*  Object;
	EIndex    Index;
} EObjectAndIndex;
EListA_t(EObjectAndIndex);

// For memory debugging
//
typedef struct
{
	ECoreObject*   Object;
	ECoreClass*    Class;

// The most important info about the Object is duplicated here, so we can
// still access it, even if the Object or the Class got damaged or freed.
//
	char*          ObjectName;
	char*          ClassName;

	EListA(,EObjectReference, References);

// Source code where Object was created.
// These members provide source code reference for first entry in CallStack, even in non-debug builds.
//
	ECallerInfo    Creation;
	ECallerInfo    Freeing;
} EObjectMemEntry;

typedef struct
{
	EObject*      Object;
	EChangeFlags  Changed;
	EObject*      NewObject;  // Replace Object with this Object, as the input, when InputChanged() is called
} EObjectChg;


typedef struct
{
	EListA(, EObjectChg, Objects);
	EBool  Propagate;    // This is set to TRUE E3dObjects_CallOutputs before calling each InputChanged() method. InputChanged() methods that do not want changes to propagate further, should set this to FALSE
	EBool  CallOutputs;  // Propagate changes from InputChanged methods, by calling further Outputs. This is deprecated, as the dependency system does optimized change propagation.
} EInterfaceCallbackStruct;


typedef struct EInterface_S  EInterface;

typedef EChangeFlags  (*EInputChangedFunc)(EInterface* PInterface, EInterfaceCallbackStruct* PCBS);
typedef EChangeFlags  (*EConnectionChangedFunc)(EInterface* PInterface, EInterfaceCallbackStruct* PCBS);

// For linking Items via Inputs and Outputs
// FIXME - consolidate this with EToolInterface
//
struct EInterface_S
{
	char*                   Name;              // Name of this input
	uint16_t                Type;              // Type of data that can be plugged in here, e.g. EResFLOAT32, or EResOBJECT
	ECoreClass*             Class;             // If Type is EResOBJECT, the class accepted (e.g. E3dMesh_class)

	ECoreObject*            Object;            // Points back to the Object that has this Interface (for the sake of _InputChanged() and for the runtime)
	ECoreObject*            ObjectComponent;   // Points back to the component Object (ObjectComponent, NodeComponent etc., e.g. Boolean)
	EInputChangedFunc       InputChanged;
	EConnectionChangedFunc  ConnectionChange;
	EPointer                ClientData;
	EChangeFlags            InputChangeFlags;  // Accumulated input changes while ReactToInputChange was FALSE (so we can react to them when ReactToInputChange is enabled)
	EBool                   ReactToInputChange;
	EBool                   Internal;          // If TRUE, this is an interface used internally (e.g. by EQX) and is not shown / counted in the GUI.
};

EListA_t(EInterface);

extern void   EInterface_Init(EInterface* PThis);
extern void   EInterface_Clear(EInterface* PThis);


static inline void  EInterfaceCallbackStruct_Init(EInterfaceCallbackStruct* PCBS)
{
	EClr_p(PCBS);
//PCBS->GUI = TRUE;
	PCBS->Propagate = TRUE;
	PCBS->CallOutputs = TRUE;
}


//
// Callbacks
//

#define ECallbackStructCore\
	int          Reason;\
	ECoreClass*  Class

// Generic Scene callback-struct
//
typedef struct
{
	ECallbackStructCore;
} ECallbackStruct;


typedef void  (*ECallbackFunc)(ECoreObject* PObject, EPointer PClientData, ECallbackStruct* PCallData);

typedef struct ECallbackRec
{
	ECallbackFunc  Func;
	EPointer       ClientData;
	EChangeFlags   EventMask;
} ECallbackRec;
EListA_t(ECallbackRec);

//========================================================
// Initialize ECallbackStruct with PReason and PClass
//========================================================
static inline void ECallbackStruct_Init(ECallbackStruct* PCBS, ECoreClass* PClass,  const int PReason)
{
	if(PClass && PClass->StructSize > 0) memset(PCBS, 0, PClass->StructSize);
	else EClr_p(PCBS);

	PCBS->Class = PClass;

	PCBS->Reason = PReason;
}



extern void   E_CallCallbacksByChangeFlags(ECoreObject* PItem, const EChangeFlags PChanged,  const ECallbackRecListA* PCallbacks,  EPointer PCallData);


// This struct is used for collecting Objects with unuqie string IDs, such as when exporting data to an ASCII file (Panda3D .egg etc.)
//
typedef struct
{
	ECoreObject*  Object;
	char*         IDString;
} EObjectAndIDString;

EListA_t(EObjectAndIDString);  // EObjectAndIDStringListA


typedef struct
{
	ECoreObject*  Object;
	EIndex        OrigIndex;  // Index in the list of e.g. ObjectComponents (so we can ensure to run updates in the proper component order)
	EChangeFlags  ChangeFlags;
} EObjectAndChangeFlags;

EListA_t(EObjectAndChangeFlags);


typedef struct
{
	ECoreObject*  Object;
	EListA_s(, EObjectAndChangeFlags, Components);
} EObjectAndComponents;

EListA_t(EObjectAndComponents);

extern EObjectAndComponents*   EObjectAndComponents_GetOrAdd(EObjectAndComponentsListA* PList, ECoreObject* PObject);
extern void                    EObjectAndComponents_Clear(EObjectAndComponentsListA* PList, const EBool PFreeList);

extern EObjectAndChangeFlags*  EObjectAndChangeFlags_GetOrAdd(EObjectAndChangeFlagsListA* PList, ECoreObject* PObject, const EChangeFlags PChangeFlags);


// Change propagation / dependency graph Node
//
typedef struct EOpNode_S  EOpNode;

struct EOpNode_S
{
	ECoreObject*    Object;
	EChangeFlags    Changed;    // OR-ed flags of for example, E3dChgMeshSHAPE

	EInterface*     Interface;  // Pointer to the input Interface of the Object (e.g. the input Interface of the Revolve ObjectComponent)

	EListA(, EOpNode*, Inputs);

	EBool           Updated;
};

EListA_t(EOpNode);

extern void      EOpNode_FreeContents(EOpNode* POpNode);
extern void      EOpNode_Free(EOpNode* POpNode);
extern EIndex    ELst_OpNodeByObjectGetIndex(EOpNode** POpNodes, const EIndex POpNodes_Count, const ECoreObject* PObject);
extern EIndex    ELst_OpNodeByInterfaceGetIndex(EOpNode** POpNodes, const EIndex POpNodes_Count, const EInterface* PInterface);
extern EOpNode*  ELst_OpNodeByInterface(EOpNode** POpNodes, const EIndex POpNodes_Count, const EInterface* PInterface);


#define EList_OpNodeByObjectGetIndex(pList, pObject)        ELst_OpNodeByObjectGetIndex(pList, pList##_Count, pObject)
#define EList_OpNodeByInterfaceGetIndex(pList, mInterface)  ELst_OpNodeByInterfaceGetIndex(pList, pList##_Count, mInterface)
#define EList_OpNodeByInterface(pList, mInterface)          ELst_OpNodeByInterface(pList, pList##_Count, mInterface)


static inline void E_ObjectChgInit(EObjectChg* PObjectChg)
{
	PObjectChg->Object    = NULL;
	PObjectChg->Changed   = 0;
	PObjectChg->NewObject = NULL;
}


//====================================================================================
// Print all references to an Object
//
// Description
//  Prints information about PObj:<BR>
//  - EObjectMEMORY_DEBUG is defined<BR>
//  - the code has debug information (debug build)<BR>
//<BR>
//  Shows where an Object was (source file + line number) and where this Object is
//  being referenced (source files + line numbers).
//  This is a macro, so it can print out the caller location, even in non-debug builds.
// 
//
// See also
//  EMemDbg_ObjectsPrint
//====================================================================================
#if EObjectMEMORY_DEBUG

#define EObject_PrintRefs(pObject, pPrintFullCallStack) do\
{\
printf("%s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);\
	EObjectMemEntry*  lEntry;const int  lResult = _EObject_Find(pObject, &lEntry);if(lEntry)\
	{\
		const int  lExecutableNameLen = E_ExecutableName ? strlen(E_ExecutableName) : 0;\
		_EObject_PrintReferences(lEntry, lResult == E_FREED, lExecutableNameLen, pPrintFullCallStack);\
	}\
} while(0)

#else

#define EObject_PrintRefs(pObject, pPrintFullCallStack) do\
{\
	const EObject*  lObject = (EObject*)(pObject);\
printf("%s() %s:%d  Object %p{%s}:%s RefCnt: %d (for detailed reference tracking info, rebuild with EObjectMEMORY_DEBUG enabled).\n", __FUNCTION__, __FILE__, __LINE__, lObject, lObject->Class->Name, lObject->Name ? lObject->Name : "-", lObject->RefCnt);fflush(stdout);\
} while(0)

#endif

extern char*  E_ExecutableName;  // For debugging

// Error response actions
//
#define E_PRINT   0x01
#define E_ASSERT  0x02

extern int    EMemDbg_Verbosity;
extern EBool  EMemDbg_TrackStaticObjects;
extern int    EMemDbg_BadRefResponse, EMemDbg_InvalidObjectResponse;

EListA(extern, EObjectMemEntry, _E_Objects);
EListA(extern, EObjectMemEntry, _E_StaticObjects);
EListA(extern, EObjectMemEntry, _E_FreedObjects);

extern void   _EObject_PrintReferences(EObjectMemEntry* PEntry, const EBool PFreed, const int PExecutableNameLen, const EBool PPrintFullCallStack);
extern int    EObject_PrintReferences(const ECoreObject* PObject, const EBool PPrintFullCallStack, const EBool PCollapseCascades);

extern void   EMemDbg_ObjectsPrint(const EBool PPrintFullCallStack, const EBool PCollapseCascades);
extern void   EMemDbg_Clear(const EBool PFreeObjects, const int PVerbosity);

extern void   EClass_PrintFullName(const ECoreClass* PClass);
extern char*  EClass_GetFullName(const ECoreClass* PClass);



extern EBool        _E_IsSubClass(const ECoreClass* PSClass, const void* PDClass);

extern EResourceList*  E_ClassCollectResources(const ECoreClass* PClass, EIndex* PNLists);

extern void       EObjectProxy_Init(EObjectProxy* PProxy);
extern void       EObjectProxy_Clear(EObjectProxy* PProxy);
extern void       EObjectProxy_ClearTargets(EObjectProxy* PProxy);
extern void       EObjectProxy_Resolve(EObjectProxy* PProxy);


extern int        EClass_Verbosity;

typedef uint16_t  ECopyFlags;

extern EObject*		EObject_New(EObjectClass* PClass);
extern EObject*		E_Copy(const void* POriginal);

extern void       _E_CallStackPrint(void* const* PCallStack, const int PCallStackDepth, const int PStartOffset, const int PExecutableNameLen);
extern int        _EObject_Find(void* PObject, EObjectMemEntry** PEntryP);
extern void       _E_Del(void* PObject);
extern void       _E_Delete(void* PObject);
extern void       _EDbg_Delete(void* PObject);
extern int        _E_ReferenceDel(EObjectMemEntry* PEntry, void* PAddress);

extern void       EObject_SetName(void* PObjectIn, char* PName, const EBool PStatic);

extern int        EObject_NumOfReferences(void* PObjectIn);

extern void       EClass_CheckAllResources(ECoreClass* PClass);
extern EIndex     EObject_ResourcesToBinaryImage(const ECoreObject* PObject, EResContext* PContext, uint8_t** PBufferPtr, ESize* PBytesAllocatedPtr, uint8_t** PBinaryImagePtr);
extern EIndex     EObject_ResourcesFromBinaryImage(ECoreObject* PObject, EResContext* PContext,  const uint8_t* PBuffer, const uint8_t* PResourcesBinaryImage,  EObjectProxyListA* PObjectProxies);

extern ECoreObject*  EResource_ToObject(const EResource* PResource, const void* PStructAddress, const void* PClass);

extern void*      EObject_FindResource(const void* PObjectV, const char* PName, const short PType);

extern EObject*   ELst_ObjectByName(EObject** PObjects, const EIndex PNumOfObjects, const char* PName);
#define EList_ObjectByName(pList, pName)  ELst_ObjectByName((EObject**)(pList), pList##_Count, pName)
#define EList_ObjectByName_s(pList, pName)  ELst_ObjectByName((EObject**)((pList).Items), (pList).Count, pName)

extern EIndex     ELst_ObjectIndexByName(EObject** PObjects, const EIndex PNumOfObjects, const char* PName);
#define EList_ObjectIndexByName(pList, pName)  ELst_ObjectIndexByName((EObject**)(pList), pList##_Count, pName)


extern EBool      _ELst_ObjectAdd(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn);
extern EBool      _ELst_ObjectAddChk(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn);
extern EBool      _ELst_ObjectInsertChk(void* PListPtr, EIndex* PNumOfPointers, EIndex PWhere, void* PObjectIn);

extern EBool      _ELst_ObjectAddA(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, void* PObjectIn);
extern EIndex     _ELst_ObjectAddAChk(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, void* PObjectIn);

extern EBool      _ELst_ObjectInsertA(void* PListPtr, EIndex* PPointers_CountP, EIndex* PPointers_CountAllocatedP, const EIndex PAllocStep, EIndex PWhere, void* PObject);
extern EBool      _ELst_ObjectInsertAChk(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, EIndex PWhere, void* PObjectIn);

extern EBool      ELst_ObjectInsert(void* PListPtr, EIndex* PNumOfPointers, EIndex PWhere, void* PObjectIn);
extern EBool      ELst_ObjectInsertA(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, EIndex PWhere, void* PObjectIn);
extern EBool      ELst_ObjectInsertAChk(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, EIndex PWhere, void* PObjectIn);

extern EBool      ELst_ObjectRemove(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn);
extern EBool      ELst_ObjectRemoveNoFree(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn);
extern int        ELst_ObjectRemoveByIndex(void* PListPtr, EIndex* PNumOfPointers, const EIndex PIndex);
extern int        _ELst_ObjectRemoveByIndexNoDel(void* PListPtr, EIndex* PNumOfPointers, const EIndex PIndex);
extern int        ELst_ObjectRemoveByIndexNoRealloc(void* PListPtr, EIndex* PNumOfPointers, const EIndex PIndex);

extern EBool      ELst_ObjectRemoveA(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, void* PObjectIn);
extern void       ELst_ObjectsFree(void* PListPtr, EIndex* PCountP);
extern void       ELst_ObjectsFreeCrossRef(void* PListPtr, EIndex* PCountP);
extern void       ELst_ObjectsFreeA(void* PListPtr, EIndex* PCountP, EIndex* PCountAP);

extern void*      ELst_StructWithObjectsAdd(void* PListPtr, EIndex* PNumOfStructs, ESize PStructSize,  const EResource* PResources, const EIndex PNResources);
extern EIndex     ELst_StructWithObjectsRemoveByIndex(void* PListPtr, EIndex* PNumOfElements, const ESize PStructSize, const EIndex PIndex,  const EResource* PResources, const EIndex PNResources);

extern EBool      _ELstMD_ObjectAdd(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn, EObjectReference* PObjectReference);
extern EBool      _ELstMD_ObjectAddA(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, void* PObjectIn, EObjectReference* PObjectReference);
extern EBool      _ELstMD_ObjectAddChk(void* PListPtr, EIndex* PNumOfPointers, void* PObjectIn, EObjectReference* PObjectReference);
extern EIndex     _ELstMD_ObjectAddAChk(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, void* PObjectIn, EObjectReference* PObjectReference);
extern EBool      _ELstMD_ObjectInsertChk(void* PListPtr, EIndex* PNumOfPointers, const EIndex PWhere, void* PObjectIn, EObjectReference* PObjectReference);

extern EBool      _ELstMD_ObjectInsertA(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, const EIndex PWhere, void* PObjectIn, EObjectReference* PObjectReference);
extern EBool      _ELstMD_ObjectInsertAChk(void* PListPtr, EIndex* PNumOfPointers, EIndex* PNumOfAllocatedPointers, const EIndex PAllocStep, const EIndex PWhere, void* PObjectIn, EObjectReference* PObjectReference);



typedef struct
{
	EObject**  Items;EIndex  Count, CountAllocated;
} EListObjectsA;


//========================================================================
// Used for saving / serializing Objects that can be referred to
//========================================================================
static inline void ERes_AddObjectFlagsAndID(FILE* PFile, EResContext* PContext, ECoreObject* PObject, const EBool PAddRef)
{
	int      LObjectID = -1;
	uint8_t  LObjectFlags = 0, LObjectIndexSize = 0;

	if(PObject)
	{
		if(PAddRef)
		{
			EIndex  LI;EList_ObjectAddAChk_s(PContext->AllObjects, 256, PObject,  LI);(void)LI;
			LObjectID = EList_PointerGetIndex_s(PContext->AllObjects, PObject);LObjectIndexSize = 4;
#if EClassDEBUG
printf("%s() %s:%d  ID %3d <%s:%s%s%s>\n", __FUNCTION__, __FILE__, __LINE__, (int)LObjectID, PObject->Class->Name, ECodeGreen, PObject->Name, ECodeNormal);fflush(stdout);
#endif
	}
#if EClassDEBUG
		else
		{
printf("%s() %s:%d  ID --- <%s:%s%s%s>\n", __FUNCTION__, __FILE__, __LINE__, PObject->Class->Name, ECodeGreen, PObject->Name, ECodeNormal);fflush(stdout);
		}
#endif
	}
	else
	{
		LObjectID = -1;LObjectIndexSize = 1;
	}

	fputc(LObjectFlags | LObjectIndexSize, PFile);
	switch(LObjectIndexSize)
	{
		case 1:
			fputc((char)LObjectID, PFile);
		break;

		case 2:
			EM_fwriteInt16_be(LObjectID, PFile);
		break;

		case 4:
			EM_fwriteInt32_be(LObjectID, PFile);
		break;

		case 8:
			EM_fwriteInt64_be(LObjectID, PFile);
		break;
	}
}


#define EFieldCopyCallback(pName, pField, pSuperClass)\
static void EFieldCopyCallback_##pName(const EObject* pSrc, EObject* pDst)\
{\
	pSuperClass*  lDst = E_DynamicCast(pDst, pSuperClass);if(lDst)\
	{\
		const pSuperClass*  lSrc = (pSuperClass*)pSrc;\
		lDst->pField = lSrc->pField;\
	}\
}


extern void    ELst_ObjectsSort_s(void* PListStruct, int (*PCompareFunc)(const void* P0, const void* P1));

extern EIndex  ERes_FromBinaryImage(EResContext* PContext, const uint8_t* PResourcesBinaryImageBufferStart, const uint8_t* PResourcesBinaryImage,  const EResource* PDictResources, const EResourceList* PResources,  void* PStructAddress,  EObjectProxyListA* PObjectProxies);
extern EIndex  ERes_ListsFromBinaryImage(EResContext* PContext,  const EResource* PDictResources,  const EResourceList* PResourceLists, const EIndex PNResourceLists,  void* PStructAddress,  const uint8_t* PBuffer, const uint8_t* PResourcesBinaryImage,  EObjectProxyListA* PObjectProxies);
extern int     ERes_ClassToTypeIndex(EResContext* PContext, ECoreClass* PClass);


#define ECbINTERNAL  0x01
#define ECbUSER      0x02


// Generic function that may be called from a macro or a script
// These may be registered from app core, or from plugins

typedef int  (*EScriptFunctionFunc)(EPointer PParameterValues);

typedef struct
{
	char*                Name;
	char*                UIName;
	char*                ToolTip;
	EScriptFunctionFunc  Func;

	EList_s(, EResource, Parameters);
	EIndex               ParametersSize;
} EScriptFunction;

extern EIndex  EObject_ResourcesBinaryImageSize(const EResContext* PContext, const ECoreObject* PObject);
extern int     EResource_GetObject(void* PStructAddress, const EResource* PResource,  EObject** PObject);
extern int     EResource_SetObjects(void* PStructAddress, const EResource* PResource,  EObject** PObjects, const EIndex PNObjects);
extern int     EResource_SetObject(void* PStructAddress, const EResource* PResource,  EObject* PObject);

extern void    EScriptFunction_Free(EScriptFunction* PScriptFunction);
extern int     EScriptFunction_Call(EScriptFunction* PScriptFunction, ...);

extern void    ECoreClass_Init(const ECoreClass* PDescriptor, ECoreClass* PClass, const uint16_t PFlags, const EBool PTrackInstances);
extern void    ECoreClass_InitNew(const ECoreClass* PDescriptor, ECoreClass* PClass, const uint16_t PFlags, const EBool PTrackInstances);
extern void    ECoreClass_InitInactiveNew(const char* PName, ECoreClass* PClass, const EBool PTrackInstances);


//================================================================
// Find an Object Resource by name, parsing all SuperClasses
//================================================================
static inline EResource* EObject_ResourceByName(const void* PObject, const char* PName)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource) return(LResource);
		LClass = LClass->SuperClass;
	}
	return(NULL);
}


//================================================================
// Set the value of a Resource in an EObject, from an EBool
//================================================================
static inline int EObject_NamedResourceSet1b(void* PObject, const char* PName, const EBool PValue)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_Set1b(PObject, LResource, PValue);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================
// Set the value of a Resource in an EObject, from an int8
//================================================================
static inline int EObject_NamedResourceSet1i8(void* PObject, const char* PName, const int8_t PValue)
{\
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_Set1i8(PObject, LResource, PValue);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================
// Set the value of a Resource in an EObject, from an int
//================================================================
static inline int EObject_NamedResourceSet1i(void* PObject, const char* PName, const int PValue)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_Set1i(PObject, LResource, PValue);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//========================================================================
// Set the value of a Resource in an EObject, from an array of ints
//========================================================================
static inline int EObject_NamedResourceSetNi(void* PObject, const char* PName,  const int* PValues, const EIndex PN)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_SetNi(PObject, LResource,  PValues, PN);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//========================================================================
// Set the value of a Resource in an EObject, from a string
//========================================================================
static inline int EObject_NamedResourceSetS(void* PObject, const char* PName,  const char* PValue)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_SetS(PObject, LResource,  PValue);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================
// Set the value of a Resource in an EObject, from a float
//================================================================
static inline int EObject_NamedResourceSet1f(void* PObject, const char* PName, const float PValue)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_Set1f(PObject, LResource,  PValue);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================
// Set the value of a Resource in an EObject, from 3 floats
//================================================================
static inline int EObject_NamedResourceSet3f(void* PObject, const char* PName,  const float P0, const float P1, const float P2)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_Set3f(PObject, LResource,  P0, P1, P2);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================================
// Set the value of a Resource in an EObject, from a list of Object pointers
//================================================================================
static inline int EObject_NamedResourceSetObjects(void* PObject, const char* PName,  void* PObjects, const EIndex PNObjects)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_SetObjects(PObject, LResource,  (EObject**)PObjects, PNObjects);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


//================================================================================
// Set the value of an Object-type Resource in an EObject
//================================================================================
static inline int EObject_NamedResourceSetObject(void* PObject, const char* PName,  void* PRObject)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_SetObject(PObject, LResource,  (EObject*)PRObject);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}

//================================================================================
// Get the value of an Object-type Resource in an EObject
//================================================================================
static inline int EObject_NamedResourceGetObject(void* PObject, const char* PName,  void* PRObject)
{
	EObject*       LObject = (EObject*)PObject;
	EObjectClass*  LClass = LObject->Class;while(LClass)
	{
		EResource*  LResource = EResource_ByName(&LClass->Resources, PName);if(LResource)
		{
			EResource_GetObject(PObject, LResource,  (EObject**)PRObject);
			return(E_SUCCESS);
		}
		LClass = LClass->SuperClass;
	}
	return(E_NOT_FOUND);
}


static inline void EObject_ResourceAssignToMember(EObject* PObject,  void* PStructAddress,const EResource* PResource,  const char* PObjectVariableName)
{
(void)PObjectVariableName;
	if(PResource)
	{
// If PStructAddress is NULL, the addresses are absolute. Otherwise they're relative to PStructAddress.
//
		uint8_t*  LVariableAddress;
		if(PStructAddress) LVariableAddress = (EPointerUInt)PStructAddress + (uint8_t*)(PResource->Address);
		else LVariableAddress = (uint8_t*)(PResource->Address);

		switch(PResource->Type & (~(EResDYNAMIC|EResCOUNT|EResCOUNT_FUNC)))
		{
			case EResOBJECT:
				{
					EObject**  LAddress = (EObject**)LVariableAddress;
					if(*LAddress != PObject)
					{
						E_DeleteChk(*LAddress);
					}

					*LAddress = PObject;
					if(PObject)
					{
					 _EM_ReferenceAdd(PObject, LAddress, PObjectVariableName,  PStructAddress,NULL,PResource->Name);
					 PObject->RefCnt+=1;
					}
				}
			break;
			default:  printf("%s() %s:%d  %sIMPLEMENT ME  %04x%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeYellow, PResource->Type & (~(EResDYNAMIC|EResCOUNT|EResCOUNT_FUNC)), ECodeNormal);fflush(stdout);break;
		}
	}
}


//================================================================
// Set the value of a Resource in an EObject, from 3 floats
//================================================================
#define EObject_NamedResourceAssignToMember(pObject,  pDstObject,pDstMember) do\
{\
	EResource*  lResource = EResource_ByName(&pDstObject->Class->Resources, #pDstMember);\
	EObject_ResourceAssignToMember((EObject*)pObject, pDstObject,lResource, #pDstObject"->"#pDstMember);\
} while(0)



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

#endif // _EClass_h
