//================================================================
// E3D library
//
// Generic "Object" header file
//
// Object is the subclass of Entity. Objects can be referenced from Nodes
// and are visible on schematics views.
// Object is the base class for:
// - Lights
// - Cameras
// - Geometries
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Nov-08 15:27:05
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Object_h
#define _E3D_Object_h


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

#ifndef _EClass_h
#include <EClass.h>
#endif

#ifndef _E3D_Types_h
#include <E3D/Types.h>
#endif

#ifndef _EImage_h
#include <Image/Image.h>
#endif


#define E3dBaseObjectMULTITHREADING  1


#ifndef _E3dMaterial
#define _E3dMaterial
typedef struct E3dMaterial_S   E3dMaterial;     // Forward-define E3dMaterial
typedef struct E3dMaterial_S*  E3dMaterialPtr;
EList_t(E3dMaterialPtr);     // E3dMaterialPtrList
EListA_t(E3dMaterialPtr);    // E3dMaterialPtrListA
#endif


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



// Selection flags for E3dModel_ObjectsUnselect(), E3dSpline_Unselect() etc.
//
#define E3dSF_MODELS           0x0001
#define E3dSF_OBJECTS          0x0002
#define E3dSF_POLYGROUPS       0x0004
#define E3dSF_POLYGONS         0x0008
#define E3dSF_EDGES            0x0010
#define E3dSF_VERTICES         0x0020
#define E3dSF_SPLINE_SEGMENTS  0x0040
#define E3dSF_ANIMATIONS       0x0080
#define E3dSF_TEXCOORDS        0x0100
#define E3dSF_TEXTUREMAPPERS   0x0200
#define	E3dSF_ALL              0x03FF


//--------------------------------
// Object selection types
//--------------------------------
#define E3dObjectSelNONE            0x0000    // The Object is not selected
#define E3dObjectSelOBJECT          0x0001    // The whole Object (Geometry, Light etc.) is selected
#define E3dObjectSelPOLYGROUP       0x0002    // One or more PolyGroups or their Polygons are selected (if the Geometry is a Mesh)
#define E3dObjectSelSPLINE_SEGMENT  0x0004    // One or more Spline segments are selected (if the Geometry is a Spline)
#define E3dObjectSelFACE_CONTOUR    0x0008    // One or more contour Splines or their Segments are selected (if the Geometry is a Face)


#ifndef _E3dModel
#define _E3dModel
typedef struct E3dModel_S   E3dModel;      // Forward-define E3dModel
typedef struct E3dModel_S*  E3dModelPtr;
EListA_t(E3dModelPtr);
#endif

#ifndef _E3dGeometry
#define _E3dGeometry
typedef struct E3dGeometry_S  E3dGeometry;  // Forward-define E3dGeometry
#endif


typedef struct
{
	E3dGeometry*   Normal;
	E3dGeometry*   NormalCollapsed;
	E3dGeometry*   Highlighted;
	E3dGeometry*   HighlightedCollapsed;
	E3dGeometry*   Outline;
	E3dCoordinate  NameXPos;
} E3dSchematicsIcons;


typedef struct
{
	const EIndex*  PointRemappingTable;
	EIndex         OldNumOfPoints, NumOfPoints;
	EChangeFlags   ChangeFlags;
} E3dObjectChanges;




typedef struct E3dObject_S       E3dObject;         // Forward-define E3dObject
typedef struct E3dObject_S*      E3dObjectPtr;
typedef struct E3dObjectClass_S  E3dObjectClass;    // Forward-define E3dObjectClass

#ifndef _E3dScene
#define _E3dScene
typedef struct E3dScene_S	  E3dScene;
#endif

struct E3dObjectClass_S
{
	EBaseClassCore(E3dObject);

	int                  (*CopyWithFlags)(const E3dObject* POrig, E3dObject* PNew, const ECopyFlags PFlags, E3dScene* PScene);

	EChangeFlags         (*UpdateForDisplay)(E3dObject* PObject, const EChangeFlags PFlags);
	void                 (*FreeRenderData)(E3dObject* PObject);
	ECoreObjectGUIFunc   GUI;

	E3dSchematicsIcons*  SchematicsIcons;
	E3dObject*           E3DIcon;
};

EListA_t(E3dObjectPtr);

typedef struct E3dWindow_S     E3dWindow;

typedef struct E3dObjectComponent_S        E3dObjectComponent;
typedef struct E3dObjectComponentClass_S   E3dObjectComponentClass;
typedef struct E3dObjectComponentClass_S*  E3dObjectComponentClassPtr;
EList_t(E3dObjectComponentClassPtr);

typedef int             (*E3dObjectComponentInitFunc)(E3dObject* PObject, E3dObjectComponent* PInfo);
typedef int             (*E3dObjectComponentFreeFunc)(E3dObject* PObject, E3dObjectComponent* PInfo);
typedef void            (*E3dObjectComponentCopyFunc)(const E3dObject* PObject, const E3dObjectComponent* PComponent, E3dObject* PNewObject, E3dObjectComponent* PNewComponent);
typedef E3dObject*      (*E3dObjectComponentUpdateFunc)(E3dObject* PObject, E3dObjectComponent* PInfo,  EUpdateFlags* PTriggeredUpdateFlags, EChangeFlags* PTriggeredSceneChangeFlagsP,  const EBool PCheckOnly);
typedef void            (*E3dObjectComponentChangeFunc)(E3dModel* PModel, E3dObject* PObject, E3dObjectComponent* PInfo, E3dObjectChanges* PChanges);
typedef void            (*E3dObjectComponentGUIFunc)(E3dObject* PObject, E3dObjectComponent* PInfo, void* PPanel, void* PDrawer, const int PAction);
typedef E3dHWDrawFlags  (*E3dObjectComponentGLDrawFunc)(E3dWindow* P3DWindow, const E3dDrawContext* PDrawContext,  E3dScene* PScene, E3dModel* PModel, E3dObject* PObject, E3dObjectComponent* PInfo);


struct E3dObjectComponentClass_S
{
	ECoreClassCore(E3dObjectComponent);

	E3dObjectComponentInitFunc    Init;
	E3dObjectComponentCopyFunc    Copy;
	E3dObjectComponentFreeFunc    Free;

	E3dObjectComponentUpdateFunc  Update1;          // Update (procedural geometry, deformer etc.)
	E3dObjectComponentChangeFunc  ChangeNew;          // Geometry changed by user etc. (Clean caches and maybe try to incorporate changes, if it's generated Geometry?)
	E3dObjectComponentGUIFunc     GUI;             // Create GUI
	uint16_t                      InternalFlags;   // Or-ed flags of EComponentVISIBLE, EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc. E.g. some components are generated internally and are not supposed to be saved to files etc.
	                                               // This may be overwritten per instance. This field is used for creating the GUI etc. when there's no instance available.
	                                               // If the EComponentSET is 0, it means this field was not initialized when registering the class, so it will be defaulted by ..ClassRegister()
	E3dObjectComponentGLDrawFunc  GLDraw;          // Custom draw function
	E3dObjectComponentGLDrawFunc  GLDrawControls;  // Custom draw function for wireframe, manipulators etc. Drawn *after* tone-mapping.  If PDisplayFlags has E3dDF_PICK set, it's called for picking (no need to set colors / shaders etc. Must do EpglPushName etc. (except for the Model->Object))
	EpImage*                      Icon;
};


#define E3dObjectComponentCore\
	EObjectCore(E3dObjectComponent);\
/* Or-ed flags of EComponentVISIBLE, EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc. E.g. some components are generated internally and are not supposed to be saved to files etc.  */\
/* These flags are set by code, in the class' constructor, etc. and are not saved into files.  */\
	uint16_t     InternalFlags;\
/* Or-ed flags of EComponentANIMATABLE, EComponentRESPOND_TO_INPUT_CHANGE. These flags may be user-settable (depending on the class) and are saved to files, etc. */\
	uint16_t     Flags;\
	EIndex       AttributeChangeCount, InputChangeCount

// General ObjectComponent structure
//
struct E3dObjectComponent_S
{
	E3dObjectComponentCore;
};


//========================================================================================
// E3dObjectComponent is a special base class, so it needs its own Free/Delete method
// This is a macro function, so we can track the caller more easily for debugging.
//========================================================================================
#define E3dObjectComponent_Free(pComponent) do\
{\
	E3dObjectComponent*  lComponent = (E3dObjectComponent*)(pComponent);\
	lComponent->BeingFreed = TRUE;\
\
	const E3dObjectComponentClass*  lClass = lComponent->Class;if(lClass)\
	{\
		if(lClass->Free) lClass->Free(NULL, lComponent);\
	}\
\
	EFreeChkClr(lComponent->BinResources);\
	_EM_ObjectMemDebugDel(lComponent);\
	EEntityCore_Free(lComponent);  /* Free the name last, so if something goes wrong, we can identify the Object while debugging */\
\
	EFree(lComponent);\
} while(0)



typedef struct
{
	EListA(, E3dObject*, ParentLinkCurves);

	E3dCoordinate  SchemBranchSizeX;     // Width of the branch rooted by this Object
	E3dCoord3      SchemTranslation,     // Parent-relative position on schematic view
	               SchemPosition,        // World-relative position on schematic view
	               ConnectionPoints[2];  // Relative to the SchemObject
	EBool          BranchExpanded, ExpandButtonActive,
								 Drawn;
} E3dSchemObject;


typedef struct E3dRPolyGroup_S   E3dRPolyGroup;
EListA_t(E3dRPolyGroup);
typedef struct E3dRPolyGroup_S*  E3dRPolyGroupPtr;
EListA_t(E3dRPolyGroupPtr);


#ifdef E3dBaseObjectMULTITHREADING
#define  E3dBaseObjectMUTEX   pthread_mutex_t  Changing_mutex;
#else
#define  E3dBaseObjectMUTEX
#endif


// Common base class for E3dObject and E3dNode
#define E3dBaseObjectCore(p)\
	EObjectCore(p);\
	ETime           ModTime;                     /* Time of last modification. Microseconds since the UNIX epoch. -1: not set */\
	char*           Notes;                       /* User-specified text UTF8 */\
	E3dSchemObject  SchemObject;\
\
	EList(, E3dLock*, Locks);      /* E.g.: the Object is being modified...        */\
\
	EList(, EInterface*, Inputs);  /* For linking Objects into a function-network  */\
	EList(, EInterface*, Outputs);\
	EBool           OutputsEnabled;              /* Outputs can be temporarily disabled to make editing faster  */\
	EChangeFlags    ChangesSinceLastOutputCall;  /* When OutputsEnabled is FALSE, change flags (e.g. E3dChgMeshSHAPE) are accumulated here, so when outputs are re-enabled and the Outputs are called, we'll know what changed. 	*/\
\
	EPointer        Tmp0;                        /* Temporary custom data. Used for fast processing / avoiding searches for Objects in arrays..                                                                                 */\
	E3dBaseObjectMUTEX


typedef struct
{
	E3dBaseObjectCore(EObject);
} E3dBaseObject;


#define E3dVisibleTO_CAMERA       0x0001
#define E3dVisibleIN_REFLECTIONS  0x0002
#define E3dVisibleALL             0x0003


// Base class for a generic E3dObject that can be instantiated from Nodes
// Those include
// - Light
// - Camera
// + Geometry
// |- PointSet
// |- Spline
// |- Face
// |- Mesh
// etc.
//
#define E3dObjectCore\
	E3dBaseObjectCore(E3dObject);\
\
	EList(, E3dObjectComponent*, Components);  /* Runtime-typed objects (e.g. torus radii, segments etc.)  */\
	EListA_s(, E3dModelPtr, Models);           /* Models that instantiate this Object                      */\
\
	uint8_t   Selection;                       /* Indicates if the Object or its components are selected. E3dObjectSelOBJECT etc.   */\
	uint16_t  VisibleFlags;                    /* Flags of E3dVisibleTO_CAMERA, E3dVisibleIN_REFLECTIONS apply if Visible is TRUE. */\
	EBool     Visible, Highlighted




// Generic instance structure
//
struct E3dObject_S
{
	E3dObjectCore;
};


// For rectangle select etc.
//
typedef struct
{
	EObject*  Object;
	int       Selection;
} E3dObjectSelection;


// E3dBaseObject
//
extern void   _E3dBaseObject_Init(E3dBaseObject* PThis);
extern int    _E3dBaseObject_Copy(E3dBaseObject* POld, E3dBaseObject* PNew);
extern void   _E3dBaseObject_Free(E3dBaseObject* PThis);

extern EIndex  E3dBaseObject_AddOutput(E3dBaseObject* PBaseObject, EInterface* POutput);
extern EIndex  E3dBaseObject_RemoveOutput(E3dBaseObject* PBaseObject, EInterface* POutput);


extern const E3dObjectClass           E3dObject_class[];
extern const E3dObjectComponentClass  E3dObjectComponent_class[];

EList_s(extern, E3dObjectComponentClassPtr, E3dObjectComponent_Classes);

extern EBool                     E3dObject_RemoveFromModels(E3dObject* PObject);

extern EIndex                    E3dObject_LockFind(const E3dObject* PObject, const E3dLock* PLock);
extern EBool                     E3dObject_LockAdd(E3dObject* PObject, E3dLock* PLock);
extern EBool                     E3dObject_LockDel(E3dObject* PObject, E3dLock* PLock);

extern E3dObjectComponentClass*  E3dObjectComponent_ClassByName(const char* PName);
extern E3dObjectComponentClass*  E3dObjectComponent_ClassRegister(E3dObjectComponentClass* PClassDescriptor);
extern void                      E3dObjectComponent_ClassDeactivate(E3dObjectComponentClass* PClass);
extern void                      E3dObjectComponent_ClassesFree(void);


extern int                       E3dObjectComponent_Remove(E3dObject* PObject, E3dObjectComponent* PInfo);
extern void                      E3dObjectComponent_RemoveAll(E3dObject* PObject);
extern void                      E3dObjectComponent_InitStatic(void* PInfoIn, E3dObjectComponentClass* PClass);
extern E3dObjectComponent*       E3dObjectComponent_New(E3dObjectComponentClass* PClass);
extern void                      E3dObjectComponent_FreeContents(E3dObjectComponent* PInfo);

extern E3dObjectComponent*       E3dObjectComponent_Add(E3dObject* PObject, E3dObjectComponentClass* PClass);
extern E3dObjectComponent*       E3dObjectComponent_AddCopy(const E3dObject* PSrcObject, E3dObjectComponent* PSrcComponent,  E3dObject* PDstObject);

extern E3dObjectComponent*       E3dObjectComponent_ByClass(E3dObject* PObject, E3dObjectComponentClass* PClass, const EBool PAdd);

extern E3dObject*                E3dObject_CustomUpdate(E3dObject* PObject, void* PInfo,  ECallFlags PCallFlags,  EChangeFlags* PTriggeredChangeFlagsP);
extern EChangeFlags              E3dObject_ComponentsCallUpdate(E3dObject* PObject,  ECallFlags PCallFlags,  EChangeFlags* PTriggeredChangeFlagsP);

extern EBool                     E3dObject_CheckType(const E3dObject* PObject, const uint32_t PObjectTypeFlags);


extern void                 E3dObject_FreeRenderData(E3dObject* PObject);

extern void                 E3dSchemObject_Init(E3dSchemObject* PSchemObject);
extern void                 E3dSchemObject_FreeContents(E3dSchemObject* PSchemObject);

extern E3dSchematicsIcons*  E3dSchematicsIcons_New(void);
extern void                 E3dSchematicsIcons_Free(E3dSchematicsIcons* PIcons);

extern void                 E3dObjectChanges_Init(E3dObjectChanges* PChanges);
extern EIndex               E3dObject_CallChangeFuns(E3dObject* PObject, E3dObjectChanges* PChanges);

extern char*                E3dCallFlags_ToString(const ECallFlags PFlags, char* PString);


extern void          (*E3dObject_CallOutputsProgressFunc)(const EOpNode* POpNode, const EIndex PCounter, const EIndex PTotalCount);

extern EChangeFlags  E3dObject_CallOutputs(E3dBaseObject* PObject, const EChangeFlags PChangeFlags);
extern EChangeFlags  E3dObjects_CallOutputs(const uint8_t PFlags,  EOpNodeListA* PObjects,  EObjectAndComponentsListA* PObjectAndComponents);

extern void           E3dDrawState_Init(E3dDrawState* PDrawState);

extern E3dObject*     E3dObject_Copy(const E3dObject* PObject, const ECopyFlags PFlags, E3dScene* PScene);
extern void           E3dObject_CopyTo(const E3dObject* PObject, E3dObject* PNewObject, const ECopyFlags PFlags, E3dScene* PScene);

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

#endif  // _E3D_Object_h
