//================================================================
// E3D library
//
// Model header file
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Sep-11 20:08:14
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Model_h
#define _E3D_Model_h


#ifndef _E3D_Node_h
#include <E3D/Node.h>
#endif

#ifndef _E3D_Animation_h
#include <E3D/Animation.h>
#endif

#ifndef _E3D_Object_h
#include <E3D/Object.h>
#endif

#ifndef _E3D_Material_h
#include <E3D/Material.h>
#endif
#ifndef _E3D_Transform_h
#include <E3D/Transform.h>
#endif


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

// This allows for per-instance settings (e.g. modifying Materials on an instance of a Mesh)
//
typedef struct
{
	E3dModel*   Model;
	E3dObject*  Object;
} E3dInstance, *E3dInstancePtr;
EListA_t(E3dInstancePtr);


typedef struct
{
	E3dBBoxGPUData  BBox;
} E3dModelGPUData;

// Note that "typedef struct E3dModel_S E3dModel;" is in Object.h, because
// this file includes it and E3dObject needs E3dModel
//

//------------------------------------------------
// Model: Transform-node with Object instances
//------------------------------------------------
struct E3dModel_S  // For forward declarations
{
	E3dNodeCore;

	EObjectID        ID;

	E3dTransformSet  TransformSet;
	E3dCoord3        TransformBase;       // For interactive transforming (values stored when interactive transform is initiated)

	EListA_s(, E3dObjectPtr, Objects);    // The Model's instantiated Geometries, Lights etc.
	EListA_s(, E3dInstancePtr, Instances);    // The Model's instantiated Geometries, Lights etc. (new way)

	uint32_t   BBoxUptodate : 1;
	E3dModelGPUData*  GPUData;
};

typedef struct
{
	E3dNode*       Node;
	E3dGeometry*   Geometry;
	EObject*       Shadeable;    // PolyGroup (in a Mesh, or in a Face)
	E3dMaterial*   OldMaterial;  // Only used internally, by the Materials plugin
} E3dShadeableRec, *E3dShadeableRecPtr;
EListA_t(E3dShadeableRecPtr);


typedef struct
{
	E3dConstraintNodeComponentCore;

	E3dNode*       AimPointNode;         // The aim point Node (NULL if E3dAimConstraintNodeComponent is on the aim point Node, in which case E3dConstraintDRIVING will be set in ConstraintFlags)

// These are only set on the affected Nodes
//
	E3dCoord3      AimVector;            // Local vector to aim toward the target (e.g. aim the local -Z axis)
	E3dCoord3      UpVector;
	E3dCoordinate  AimDistance;          // Distance between AffectedNodes and the Aim Node
	E3dCoord3      AimDirection;         // The unit length vector of the line-of-sight (for distance setting). It points from the AffectedNodes to the AimNode
	E3dCoordinate  Latitude, Longitude;  // Orbital angles (y,x)
	E3dCoordinate  BankAngle;            // Relative to UpVector!
} E3dAimConstraintNodeComponent;


typedef struct
{
	E3dNodeComponentCore;

// E3dJointNodeInfo part
//
	E3dMatrix       JointOrientMatrix;             // Matrix to set default orientation of a joint (so the X axis always points along the bone)
	E3dMatrix       PostRotateMatrix;              // Matrix to apply after normal rotations
	E3dCoordinate   AngleXMin, AngleXMax,          // Rotation angle limits
	                AngleYMin, AngleYMax,
	                AngleZMin, AngleZMax;
	E3dCoord3       AngularDampening;

	E3dCoordinate   BoneWidth;                     // Just for drawing (for now?)

	E3dMatrix       LocalToWorldMatrixNoOrient;    // LocalToWorld Matrix without the JointOrientMatrix
	EBool           XRotationLimited, YRotationLimited, ZRotationLimited;

	EBool           DrawOver;                      // Draw this skeleton over Geometries (no Z test), so it's always fully visible
} E3dJointNodeInfo;


typedef struct
{
	E3dNodeComponentCore;

// E3dIKEffectorNodeInfo part
//
	int  Iterations;
} E3dIKEffectorNodeInfo;


#define E3dLargestNode  E3dModel


typedef struct
{
  E3dCoord3      Position, AimPoint, UpVector;
	E3dCoordinate  FieldOfView;
	E3dCoord2      Mag;

	E3dCoordinate  Lon, Lat, AimDistance, BankAngle;
} E3dCameraTransform;




//----------------------------------------------------------------
// Function prototypes
//----------------------------------------------------------------

//--------------------------------
// Model.c
//--------------------------------
extern E3dNodeClass  E3dModel_class[];

extern const EResource  E3dModel_TransformSet_EulerRotation_Angles_X[];
extern const EResource  E3dModel_TransformSet_EulerRotation_Angles_Y[];
extern const EResource  E3dModel_TransformSet_EulerRotation_Angles_Z[];

extern E3dObjectComponentClass*  E3d_VectorObjectComponentClass;

extern EBool       E3dModel_GetBoundingBox(const E3dModel* PModel, const uint32_t PWhatToInclude, const EBool PApplyScale,  E3dBBox* PBBox);
extern EBool       E3dModel_GetTransformedBoundingBox(const E3dModel* PModel, const E3dMatrix PMatrix, const uint32_t PWhatToInclude,  E3dBBox* PBBox);

extern EBool       E3dModel_GetBoundingSphere(const E3dModel* PModel, const uint32_t PWhatToInclude, const EBool PApplyScale,  E3dCoord3* PCenterPtr, E3dCoordinate* PRadiusPtr);

extern void        E3dModel_ResetTransforms(E3dModel* PModel);

extern EBool       E3dModel_OrientBone(E3dModel* PJoint, E3dNode* PParentNode,  const E3dCoordinate PX, const E3dCoordinate PY, const E3dCoordinate PZ,  const E3dCoordinate PZAxisX, const E3dCoordinate PZAxisY, const E3dCoordinate PZAxisZ);

extern EIndex      E3dModel_ObjectAppend(E3dModel* PModel, E3dObject* PObject, const EBool PCheckIfExists);
extern E3dObject*  E3dModel_ObjectInsert(E3dModel* PModel, E3dObject* PObject, const EIndex PWhere);
extern EIndex      E3dModel_ObjectGetIndex(E3dModel* PModel, E3dObject* PObject);
extern void        E3dModel_ObjectRemove(E3dModel* PModel, E3dObject* PObject);

extern E3dObject*  E3dModel_ObjectAddNew(E3dModel* PModel, E3dObjectClass* PClass);
extern void        E3dModel_ObjectsRemove(E3dModel* PModel);

extern void          E3dModel_ObjectsSelect(E3dModel* PModel);
extern EChangeFlags  E3dModel_ObjectsUnselect(E3dScene* PScene, E3dModel* PModel,  E3dObject** PSkipTheseObjects, const EIndex PSkipTheseObjects_Count,  const uint32_t PFlags, const EBool PNotify);

extern void        E3dModel_InstancesRemove(E3dModel* PModel);


extern EChangeFlags  E3dObject_Unselect(E3dScene* PScene, E3dObject* PObject, const uint32_t PFlags, const EBool PNotify);


extern void          E3dModel_CollectMaterials(E3dModel* PModel, E3dMaterialPtrListA* PMaterials);

extern E3dCoord3     E3dModel_GetGlobalPosition(E3dModel* PModel);
extern EBool         E3dModel_Tesselate(E3dModel* PModel, const EBool PSelectionOnly, const EBool PDoConvex);

extern void          E3dNode_FreeRenderData(E3dNode* PNode);

extern E3dObject*    E3dModel_GetObjectByClass(E3dModel* PModel, const void* PClass);


extern E3dModel*     E3dObject_GetSelectingModel(const E3dObject* PObject, const EBool PVisibleOnly);
extern E3dModel*     E3dObject_GetVisibleModel(const E3dObject* PObject);


extern E3dNode*      E3dNode_Copy(E3dScene* PScene, E3dNode* PNode, const EFlags PCopyFlags, const EBool PInstance, const uint32_t PObjectTypeFlags, const EBool PVisibleOnly, const EBool PCheckSelection);


//--------------------------------
// Scene.c
//--------------------------------
extern E3dMaterial*  E3dObject_GetDrawingMaterial(const E3dModel* PInstantiatingModel, const E3dObject* PObject, const EBool PFallBackToDefaultMaterial);

//--------------------------------
// Constraints/Aim.c
//--------------------------------
extern E3dNodeComponentClass  E3dAimConstraintNodeComponent_classdesc;

extern void      E3d_CalcUpVector(const E3dCoord3* P3Position, const E3dCoord3* PAimPoint, const E3dCoordinate PBankAngle, E3dCoord3* PUpVector);
extern int       E3dModel_GetAim(const E3dScene* PScene, const E3dModel* PCameraModel,  E3dCoord3* PAimPointP, E3dCoord3* PAimDirectionP, E3dCoordinate* PAimDistanceP, E3dCoord3* PUpVectorP, E3dCoordinate* PBankAngleP);
extern E3dNode*  E3d_AimNodeFind(const E3dScene* PScene, E3dNode* PAffectedNode, E3dAimConstraintNodeComponent** PInfoP);
extern void      E3d_CalcOrbit(const E3dCoord3* P3Position, const E3dCoord3* PAimPosition,  E3dCoordinate* PLongitudeP, E3dCoordinate* PLatitudeP, E3dCoordinate* PViewDistanceP);
extern int       E3d_AimConstraintCalcOrbit(E3dScene* PScene, E3dNode* PAffectedNode, E3dNode* PAimNode, E3dCoordinate* PLongitudeP, E3dCoordinate* PLatitudeP);
extern void      E3d_Orbit(E3dCoord3* P3Position, const E3dCoord3* PAimPosition,  E3dCoordinate PLongitude, E3dCoordinate PLatitude);
extern void      E3d_Track(E3dMatrix PLocalToWorldMatrix, const E3dCoordinate PAimDistance, const E3dCoordinate PFieldOfView, const E3dCoordinate PViewPortSizeY, const E3dCoordinate PTrackStep,  const int PPtrXDiff, const int PPtrYDiff,  E3dCoord3* PMove);
extern void      E3dAimConstraint_Orbit(E3dAimConstraintNodeComponent* PAimInfo, E3dNode* PAffectedNode, E3dNode* PAimNode, const E3dCoordinate PLongitude, const E3dCoordinate PLatitude);
extern void      E3d_AimConstraintUpdateMatrices(E3dModel* PCameraModel,  const E3dCoord3* P3Position, const E3dCoord3* PAimPoint,  const E3dCoord3* PAimVector, const E3dCoord3* PUpVector, const E3dCoordinate PBankAngle,  const EBool PSetTranslation);
extern void      E3d_AimConstraintUpdate(E3dScene* PScene, E3dModel* PAffectedModel,  const E3dCoord3* P3Position, const E3dCoord3* PAimPoint, const E3dCoord3* PUpVector, const E3dCoordinate PBankAngle);
extern void      E3dAimConstraint_SetDistance(E3dScene* PScene, E3dAimConstraintNodeComponent* PAimInfo, E3dNode* PAffectedNode, E3dNode* PAimNode, const E3dCoordinate PDistance);
extern void      E3dAimConstraint_CalcUpVector(E3dAimConstraintNodeComponent* PInfo, E3dNode* PAffectedNode, E3dNode* PAimNode);


//--------------------------------
// Object.c
//--------------------------------
extern void  E3dObject_CollectMaterials(E3dModel* PModel, E3dObject* PObject, E3dMaterialPtrListA* PMaterials);


//--------------------------------
// Panel/Schematics.c
//--------------------------------
extern void  E3dNodeHrc_RefreshSchemPositions(E3dNode* PRootNode);


//--------------------------------
// Panel/3DPanel.c
//--------------------------------
extern EChangeFlags  E3dObject_GetChangeFlagsByClass(const E3dObject* PObject);
extern EChangeFlags  E3dObject_GetTransformChangeFlagsByClass(const E3dObject* PObject);

extern EChangeFlags  E3dModel_GetChangeFlagsByObjects(const E3dModel* PModel);
extern EChangeFlags  E3dNodeHrc_GetChangeFlagsByObjects(const E3dNode* PRootNode);

extern EChangeFlags  E3dModel_GetTransformChangeFlagsByObjects(const E3dModel* PModel);

extern EChangeFlags  E3dNodeHrc_GetTransformChangeFlagsByObjects(const E3dNode* PRootNode);


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

#endif	// _E3D_Model_h
