/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Node-related functions header file					*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Dec-17 23:14:07					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#ifndef _E3DModel_h
#define _E3DModel_h


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

#ifndef _E3DGeometry_h
#include <E3D/Geometry.h>
#endif

#ifndef _E3DMaterial_h
#include <E3D/Material.h>
#endif

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


// Size of a Model representation on the Schematics view
//
#define	E3dSCHEM_MODEL_XSIZE			4.0
#define	E3dSCHEM_MODEL_YSIZE			1.0
#define	E3dSCHEM_MODEL_ZSIZE			0.5


//--------------------------------
// Node types
//--------------------------------
enum
{
 E3dMDL_NORMAL=0,		// A normal Model
 E3dMDL_INSTANCE,		// Another instance of a Model using the same Geometries
 E3dMDL_LIGHT,			// Pseudo Model for a light source
 E3dMDL_LIGHT_INTEREST,		// Pseudo Model for a light source interest point (spotlight)
 E3dMDL_CAMERA,			// Pseudo Model for the camera
 E3dMDL_CAMERA_INTEREST,	// Pseudo Model for the camera interest point
 E3dMDL_JOINT,			// Joint of a skeleton hierarchy
 E3dMDL_BONE,			// Bone of a skeleton hierarchy (new, more flexible than, JOINT. Bones can move too, not just rotate at the joints)
 E3dMDL_FORCE,			// Pseudo Model for a force
 E3dMDL_WIND,			// Pseudo Model for a wind
 E3dMDL_TEXTURE_PROJECTOR	// This is not an actual Node type, just for E3d_DrawMesh
};



#define E3dMDL_BEFORE		 1		// For pre-calculated matrix PUSHs and POPs
#define E3dMDL_AFTER		 (1<<1)

// Model selection types
//
enum
{
 E3dSEL_NONE=0,
 E3dSEL_GEOMETRY,	// One or more of the Geometries of the Model is selected or a sub-geometry (e.g. a PoyGroup) is selected in those Geometries
 E3dSEL_NODE,		// Model is selected independently of it's relatives
 E3dSEL_BRANCH,		// This Model is in a selected branch
 E3dSEL_BRANCH_ROOT,	// This Model is in a selected branch and this is the root of it
};



typedef struct	E3dModelInfo_S	E3dModelInfo;

typedef int	(*E3dModelEditProc)(E3dModel*, E3dModelInfo*);
typedef int	(*E3dModelProc)(E3dModel*, E3dModelInfo*);


typedef struct
{
 char*			Name;
 unsigned int		StructSize;
 E3dModelEditProc	EditProc;
 E3dModelProc		RemoveProc;		// This gets called when the Model is removed from the scene
 E3dModelProc		DestroyProc;
 EResource*		Resources;
} E3dModelClass;


#define E3dModelInfoCore()\
 E3dModelClass*	Class

struct E3dModelInfo_S
{
 E3dModelInfoCore();
};



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



#define E3dModelCore()\
 int		RefCnt;				/* Reference count				*/\
\
 char*		Name;\
 char*		FileName;\
\
 int		Type;\
\
 int		LockCount;			/* Indicates how many procedures are editing this Model	*/\
 unsigned int	Selection;\
\
 unsigned int	NumOfInfoRecords;		/* Number of type-specific info structures	*/\
 E3dModelInfo**	Info;				/* Custom class data				*/\
\
 unsigned int	NumOfAnimations;		/* Number of animation structures		*/\
 E3dAnimation**	Animations;			/* Animation structures				*/\
\
 unsigned int	NumOfGeometries;\
 E3dGeometry**	Geometries;			/* Model's Geometries (E3dMesh, E3dSpline ...)	*/\
\
 E3d3DPosition	Translation;\
 E3d3DPosition	Scaling;\
 E3dRotation	Rotation;\
 char		RotationOrder;			/* Rotation order				*/\
 E3dQuaternion	Orientation;\
 E3dMatrix	LocalToWorldMatrix;		/* Local->World matrix for faster display if only the camera moves	*/\
 E3dMatrix	NormalLocalToWorldMatrix;	/* Local->World matrix for normals (no scaling)	*/\
\
 E3d3DPosition	BBoxMin, BBoxMax;		/* Bounding box					*/\
\
 E3dCoordinate	SchemBranchXSize;		/* Width of the branch rooted by this Model	*/\
 E3d3DPosition	SchemTranslation;		/* Parent-relative position on schematic view	*/\
 E3d3DPosition	SchemPosition;			/* World-relative position on schematic view	*/\
\
 E3d3DPosition	TransformBase;			/* For interactive transforming	*/\
\
 E3dModel*	Parent;				/* Hierarchy links	*/\
 E3dModel*	PrevSibling;\
 E3dModel*	NextSibling;\
 E3dModel*	Child;\
 char		PopN, PushN;\
 E3dModel*	Prev;				/* Linking data	*/\
 E3dModel*	Next;\
 E3dPointer	UserData;\
\
 EBool		MatrixNew;			/* Matrix is different from the previously used one, so load it...	*/\
 EBool		Visible


//----------------------------------------
// Model: the Transform-node
//----------------------------------------
struct E3dModel_S		// For forward declarations
{
 E3dModelCore();
};



typedef struct E3dJointModel
{
// E3dModel part
//
 E3dModelCore();

// E3dJointModel part
//
 E3dMatrix		JointOrientMatrix;		// Matrix to set default orientation of a joint (so the X axis always points along the bone)
 E3dAngle		XAngleMin, XAngleMax,		// Rotation angle limits
			YAngleMin, YAngleMax,
			ZAngleMin, ZAngleMax;
 E3dAngle		XDampening, YDampening, ZDampening;
 E3dMatrix		WorldToDefaultMatrix;		// The inverse of the LocalToWorld Matrix at the time of the call to _DCB_SkeletonSetDefaultTransform
 E3dMatrix		SkinningMatrix;			// The LocalToWorld * WorldToDefaultMatrix
 E3dGeometry*		Skin;
 EBool			XRotationLimited, YRotationLimited, ZRotationLimited;
} E3dJointModel;








#define E3dM_IsModelSelected(mModel, mModelSelected)\
    switch((mModel)->Selection)\
    {\
     case E3dSEL_NODE:\
     case E3dSEL_BRANCH:\
     case E3dSEL_BRANCH_ROOT:\
      mModelSelected=TRUE;\
     break;\
\
     default:	mModelSelected=FALSE;break;\
    }




//================================================================================
// Activation callback template for a Model with construction-history
//================================================================================
#define E3dTpl_ModelACB_CHist(mType, mPrefix)\
 {\
  EBool	mSuccess;\
\
  if(mPrefix##Model) return;\
\
  mSuccess=FALSE;\
  if((mPrefix##Model=mPrefix##Get(NULL, &mPrefix##Info, E3dGF_ALL))!=NULL)\
  {\
   mSuccess=E3d_SceneAddModelHrc(E3d_Scene, mPrefix##Model);\
   E3dp_SceneLayoutOnSchematics(E3d_Scene);\
  }\
\
  mPrefix##CreateMode=TRUE;\
  if(mSuccess)\
  {\
   mType##Info*	LInfo=(mType##Info*)E3d_ModelInfoByClass(mPrefix##Model, mPrefix##Info.Class);\
\
   if(((EguiPushButtonCallbackStruct*)LCallData)->Reason==ECR_OPTIONS) mPrefix##PopupDialog(LInfo);\
   else\
   {\
    mPrefix##Model=NULL;\
   }\
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
  }\
 }


//================================================================
// Minimal EditProc template for a Model class
//================================================================
#define E3dTpl_ModelMinEditProc(mType, mPrefix)\
/* If this Model has no ModelInfo yet, create one and initialize it	*/\
/**/\
 if(LInfo==NULL)\
 {\
  E3dModelInfo*	LInfo=E3d_ModelInfoAdd(LModel, mPrefix##Info.Class);\
  memcpy(LInfo, &mPrefix##Info, sizeof(mType##Info));\
  return(E3dEDITP_INFO_ADDED);\
 }



//================================================================================
// EditProc template for a Model with a simple, self-contained
// construction-history (no inputs)
//================================================================================
#define E3dTpl_ModelEditProc_CHist(mType, mPrefix)\
{\
/* If LInfo is NULL, add a new Info record to the Geometry	*/\
 if(LInfo==NULL)\
 {\
  LInfo=E3d_ModelInfoAdd(LModel, mPrefix##Info.Class);\
  memcpy(LInfo, &mPrefix##Info, sizeof(mType##Info));\
  return(E3dEDITP_INFO_ADDED);\
 }\
 else\
 {\
/* If the same Model is still being edited, return	*/\
/**/\
  if(mPrefix##Model==LModel) return(E3dEDITP_IN_USE);\
\
  mPrefix##CreateMode=FALSE;\
\
  if(mPrefix##Model)\
  {\
   mPrefix##Model->LockCount-=1;		/* Unlock currently edited Model	*/\
   if(mPrefix##Model->LockCount==0) E3d_ModelUpdateForDisplay(mPrefix##Model, E3dGF_LOCKUNLOCK);\
\
/* _PopupDialog will increment this, but the dialog is already up...	*/\
/**/\
   _Plugin->LockCount-=1;\
  }\
\
  mPrefix##Model=LModel;mPrefix##Model=LModel;\
  LModel->LockCount+=1;if(LModel->LockCount==1) E3d_ModelUpdateForDisplay(LModel, E3dGF_LOCKUNLOCK);\
  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
\
  mPrefix##PopupDialog((mType##Info*)(LInfo));\
  return(E3dEDITP_EDITING);\
 }\
}



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

//--------------------------------
// Model.c
//--------------------------------
extern EBool		E3d_ModelGetBoundingBox(E3dModel* LModel, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);

extern EBool		E3d_ModelGetTransformedBoundingBox(E3dModel* LModel, E3dMatrix LMatrix, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);

extern void		E3d_ModelResetTransforms(E3dModel* LModel);
extern void		E3d_ModelGetLocalMatrices(E3dModel* LModel, E3dMatrix LMatrix, E3dMatrix LNormalMatrix);

extern E3dModel*	E3d_ModelAllocate(char* LName);


extern E3dJointModel*	E3d_JointModelAllocate(char* LName);
extern void		E3d_JointModelUpdateSkinningMatrix(E3dJointModel* LJointModel);


extern E3dGeometry*	E3d_ModelAppendGeometry(E3dModel* LModel,E3dGeometry* LGeometry);
extern void		E3d_ModelRemoveGeometry(E3dModel* LModel, E3dGeometry* LGeometry);

extern E3dModelInfo*	E3d_ModelInfoAdd(E3dModel* LModel, E3dModelClass* LClass);

extern E3dGeometry*	E3d_ModelAddGeometry(E3dModel* LModel, int LGeoType, char* LGeoName);
extern void		E3d_ModelRemoveGeometries(E3dModel* LModel);

extern void		E3d_ModelFree(E3dModel* LModel);


extern void		E3d_ModelCopyTransform(E3dModel* LSModel, E3dModel* LDModel, EBool LTransformCompensation);



extern int		E3d_ModelNumOfSelectedGeometries(E3dModel* LModel);


extern E3dMaterial*	E3d_ModelInheritMaterial(E3dModel* LModel);

extern E3dMaterial*	E3d_GeometryGetMaterial(E3dGeometry* LGeometry, EBool LSelectedSubGeo);

extern E3dMaterial*	E3d_ModelGetMaterial(E3dModel* LModel, EBool LSelectedSubGeo);
extern int		E3d_ModelRemoveMaterial(E3dModel* LModel, E3dMaterial* LMaterial);
extern E3dMaterial**	E3d_ModelCollectMaterials(E3dModel* LModel, unsigned int* LNumOfMaterialsPtr);


extern int		E3d_ModelMap2DTextures(E3dModel* LModel);


extern void		E3d_ModelConnectChild(E3dModel* LParent, E3dModel* LChild);
extern void		E3d_ModelDisconnectFromHierarchy(E3dModel* LModel);

extern int		E3d_ModelInfoRemove(E3dModel* LModel, E3dModelInfo* LInfo);
extern int		E3d_ModelInfoRemoveAll(E3dModel* LModel);

extern E3dModelInfo*	E3d_ModelInfoByClass(E3dModel* LModel, E3dModelClass* LClass);
extern E3dModelClass*	E3d_ModelClassFindByName(char* LName);
extern E3dModelClass*	E3d_ModelClassRegister(E3dModelClass* LClassTemplate);
extern void		E3d_ModelClassDeactivate(E3dModelClass* LClass);
extern void		E3d_ModelClassRemove(E3dModelClass* LClass);

extern EBool		E3d_ModelAppendAnimation(E3dModel* LModel, E3dAnimation* LAnimation);
extern int		E3d_ModelRemoveAnimation(E3dModel* LModel, E3dAnimation* LAnimation);
extern int		E3d_ModelRemoveAllAnimations(E3dModel* LModel);



extern E3d3DPosition	E3d_ModelGetGlobalPosition(E3dModel* LModel);
extern EBool		E3d_ModelTesselate(E3dModel* LModel, EBool LDoConvex);

extern void		E3d_UpdateDrawingMaterial(E3dGeometry* LGeometry, E3dMaterial* LMaterial, E3dMaterial** LMaterialPtr);


extern void		E3d_ModelUpdateForDisplay(E3dModel* LModel, unsigned int LFlags);
extern void		E3d_ModelUpdateMaterialsForDisplay(E3dModel* LModel);

extern void		E3d_ModelFreeRenderData(E3dModel* LModel);

extern E3dModel*	E3d_GeometryGetSelectingModel(E3dGeometry* LGeometry);

extern E3dGeometry*	E3d_ModelGetGeometryByType(E3dModel* LModel, int LGeoType);

extern void		E3d_ModelAddLock(E3dModel* LModel);
extern void		E3d_ModelDelLock(E3dModel* LModel);
extern void		E3d_ModelsAddLock(E3dModel** LModels, unsigned int LNumOfModels);
extern void		E3d_ModelsDelLock(E3dModel** LModels, unsigned int LNumOfModels);


//--------------------------------
// ModelHrc.c
//--------------------------------
extern void		E3d_ModelHrcFree(E3dModel* LRootModel, EBool LAllTypes);
extern void		E3d_ModelHrcCollapseBranch(E3dModel* LModel, EBool LFreezeTransforms);
extern void		E3d_ModelHrcFree(E3dModel* LModel,EBool LAllTypes);
extern E3dMaterial**	E3d_ModelHrcCollectMaterials(E3dModel* LRootModel, unsigned int* LNumOfMaterialsPtr);
extern void		oldE3d_ModelHrcRemoveEmptyGeometry(E3dModel* LRootModel);
extern E3dModel*	E3d_ModelHrcDuplicate(E3dModel* LRootModel);
extern void		E3d_ModelHrcRefreshMaterialInheritance(E3dModel* LModel);

extern void		E3d_ModelHrcMap2DTextures(E3dModel* LRootModel);


extern void		E3d_ModelHrcRefreshHierarchy(E3dModel* LRootModel);
extern void		E3d_ModelHrcRefreshMatrices(E3dModel* LBranchRootModel);
extern void		E3d_ModelHrcRefreshMatricesNoScaling(E3dModel* LRootModel);

extern void		E3d_ModelHrcFreezeScaling(E3dModel* LBranchRootModel);

extern void		E3d_ModelHrcCallRemoveProcs(E3dModel* LRootModel);

extern E3dModel*	E3d_ModelHrcBranchGetLastNode(E3dModel* LBranchRootModel);
extern E3dModel*	E3d_ModelHrcBranchGetNodeAfter(E3dModel* LBranchRootModel);


extern E3dModel*	E3d_ModelHrcBranchDisconnectFromParent(E3dModel* LModel, EBool LCompensateForTransforms);


extern void		E3d_ModelHrcCreateRenderablePolygons(E3dModel* LModel, EBool LDoConvex);


extern void		E3d_ModelHrcCreateEdgesFromPolyData(E3dModel* LRootModel);

extern void		E3d_ModelHrcUpdateForDisplay(E3dModel* LModel, unsigned int LFlags);
extern void		E3d_ModelHrcUpdateMaterialsForDisplay(E3dModel* LModel);



extern void		E3d_ModelHrcSkeletonSetDefaultTransform(E3dModel* LModel);


#ifdef USEOpenGL
extern void		E3d_ModelHrcRefreshMatricesGL(E3dModel* LRootModel);
extern void		E3d_ModelRemoveGLDisplayLists(E3dModel* LModel);
#endif // USEOpenGL


//--------------------------------
// Panel/Schematics.c
//--------------------------------
extern int		E3d_ModelHrcLayoutOnSchematics(E3dModel* LRootModel, E3dCoordinate* LXSizeRet, E3dCoordinate* LYSizeRet);
extern void		E3d_ModelHrcRefreshSchemPositions(E3dModel* LRootModel);








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

#endif	// _E3DModel_h
