/*======================================================================================*/
/* 3DLib										*/
/*											*/
/* General Geometry-related functions header file					*/
/*											*/
/* AUTHOR:	Gabor Nagy								*/
/* DATE:	1996-Dec-28 23:52:42							*/
/*											*/
/* 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================================*/
#ifndef _E3DGeometry_h
#define _E3DGeometry_h


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

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

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



/*------------------------------*/
/* Initialize Geometry fields	*/
/*------------------------------*/
#define E3dM_GeometryDefault(mGeometry)\
{\
 (mGeometry)->RefCnt=0,\
 (mGeometry)->LockCount=0,\
 (mGeometry)->Name=NULL,\
 (mGeometry)->NumOfInfoRecords=0,\
 (mGeometry)->Info=NULL,\
 (mGeometry)->Selection=E3dSEL_NONE,\
 (mGeometry)->Visible=TRUE,\
 (mGeometry)->Inputs=NULL,(mGeometry)->NumOfInputs=0,\
 (mGeometry)->Outputs=NULL,(mGeometry)->NumOfOutputs=0,\
 (mGeometry)->Models=NULL,(mGeometry)->NumOfModels=0,\
 (mGeometry)->CastsShadows=TRUE,\
 (mGeometry)->ReceivesShadows=TRUE,\
 (mGeometry)->LODStep=0,\
 (mGeometry)->LODReference=0.0,\
 (mGeometry)->LODProc=NULL,\
 (mGeometry)->LODs=NULL,\
 (mGeometry)->NumOfLODs=0,\
 (mGeometry)->AutoLOD=TRUE,\
 (mGeometry)->BBoxUptodate=FALSE;\
}

#define E3dM_LODRefCmp(mIdx)	(LGeometry->LODs[mIdx])->LODReference<mLODRef

#define E3dM_GeometryGetLODForDrawing(mGeometry)\
 if(mGeometry->AutoLOD)\
 {\
  if(LCamera)\
  {\
   if(mGeometry->LODs)\
   {\
    E3dCoordinate	mLODRef, mX=LModel->LocalToWorldMatrix[M30], mY=LModel->LocalToWorldMatrix[M31], mZ=LModel->LocalToWorldMatrix[M32];\
    E3dCoordinate	mXP, mYP, mZP;\
\
    E3dM_MatrixTransform3x4(LCamera->WorldToViewerMatrix, mXP, mYP, mZP);\
\
\
    mLODRef=-mZP*LSizeFactor;\
\
    if(mLODRef > mGeometry->LODs[0]->LODReference)\
    {\
     EM_BinSearch(LGeometry->NumOfLODs, E3dM_LODRefCmp);\
     if(LIndex>(mGeometry->NumOfLODs)) LIndex=mGeometry->NumOfLODs;\
     LGeometry=LGeometry->LODs[LIndex-1];\
/*printf("AutoLOD %f LOD # %d\n", mLODRef, LIndex);fflush(stdout);*/\
    }\
   }\
  }\
 }\
 else\
 {\
  if(mGeometry->LODs)\
  {\
   if(mGeometry->LODStep) mGeometry=mGeometry->LODs[mGeometry->LODStep-1];\
  }\
 }



#define E3dM_GeometryPickLODForDrawing(mGeometry, mWorldToViewerMatrix)\
 if(mGeometry->AutoLOD)\
 {\
  if(mGeometry->LODs)\
  {\
   E3dCoordinate	mLODRef, mX=LModel->LocalToWorldMatrix[M30], mY=LModel->LocalToWorldMatrix[M31], mZ=LModel->LocalToWorldMatrix[M32];\
   E3dCoordinate	mXP, mYP, mZP;\
\
   E3dM_MatrixTransform3x4(mWorldToViewerMatrix, mXP, mYP, mZP);\
\
\
   mLODRef=-mZP*LSizeFactor;\
\
   if(mLODRef > mGeometry->LODs[0]->LODReference)\
   {\
    int	LIndex;\
\
    EM_BinSearch(LGeometry->NumOfLODs, E3dM_LODRefCmp);\
    if(LIndex>(mGeometry->NumOfLODs)) LIndex=mGeometry->NumOfLODs;\
    LGeometry=LGeometry->LODs[LIndex-1];\
printf("AutoLOD %f LOD # %d\n", mLODRef, LIndex);fflush(stdout);\
   }\
  }\
 }\
 else\
 {\
  if(mGeometry->LODs)\
  {\
   if(mGeometry->LODStep) mGeometry=mGeometry->LODs[mGeometry->LODStep-1];\
  }\
 }



typedef struct
{
 E3dCoordinate	U, V;
} E3dUV;




/*------------------------------*/
/* Geometry types		*/
/*------------------------------*/
enum
{
 E3dGEO_NULL=0,
 E3dGEO_POINTS,			// Separate colored points
 E3dGEO_MESH,			// A polygon Mesh
 E3dGEO_SKINMESH,		// A polygon Mesh affected by a skeleton hierarchy
 E3dGEO_SUBDIVISION_SURFACE,	// A subdivision-surface	
 E3dGEO_SPLINE,			// Spline (Linear, Bezier, Cardinal, BSpline, NURBS)
 E3dGEO_FACE,			// Face (Bezier, Cardinal, BSpline, NURBS)
 E3dGEO_PATCH			// Patch (Bezier, Cardinal, BSpline, NURBS)
};

#define E3dGEO_ANY	E3dGEO_NULL


#define caseE3dMESH()\
 case E3dGEO_MESH:\
 case E3dGEO_SKINMESH:\
 case E3dGEO_SUBDIVISION_SURFACE



// Selection flags for E3d_UnselectModelGeometries(), E3d_SplineUnselect() etc.
//
#define E3dSF_MODELS		0x01
#define E3dSF_GEOMETRIES	0x02
#define E3dSF_POLYGROUPS	0x04
#define E3dSF_POLYGONS		0x08
#define E3dSF_EDGES		0x10
#define E3dSF_VERTICES		0x20
#define E3dSF_SPLINE_SEGMENTS	0x40
#define	E3dSF_ALL		0x7F


/*------------------------------*/
/* Geometry clone flags		*/
/*------------------------------*/
#define E3dCLONE_MATERIALS		0x01
#define E3dCLONE_LODS			0x02
#define E3dCLONE_INFO			0x04
#define E3dCLONE_ALL			0x07

/*------------------------------*/
/* Geometry selection types	*/
/*------------------------------*/
enum
{
 E3dGSEL_NONE=0,		// The Geometry is not selected
 E3dGSEL_GEOMETRY,		// The whole Geometry is selected
 E3dGSEL_POLYGROUP,		// One or more PolyGroups or their Polygons are selected (if the Geometry is a Mesh)
 E3dGSEL_SPLINE_SEGMENT,	// One or more Spline segments are selected (if the Geometry is a Spline)
 E3dGSEL_FACE_CONTOUR		// One or more contour Splines or their Segments are selected (if the Geometry is a Face)
};


// "Reasons" flags for E3d_GeometryUpdateForDisplay()
// These flags tell E3d_GeometryUpdateForDisplay() what should
// be updated in the rendering-specific internal structures
//
#define E3dGF_LOCKUNLOCK	0x0001	// Geometry was locked/unlocked, update wireframe color
#define E3dGF_CV_POSITION	0x0002	// Spline CV position(s) changed
#define E3dGF_VERTEX_POSITION	0x0004	// Vertex position(s) changed
#define E3dGF_VERTEX_NORMAL	0x0008	// Vertex normal(s) changed
#define E3dGF_POLYGON_NORMAL	0x0010	// Polygon normal(s) changed
#define E3dGF_REMOVE_STRIPS	0x0020	// Remove triangle strips
#define E3dGF_TOPOLOGY		0x0040
#define E3dGF_TEXTURE_ST	0x0080				// Update texture coordinates on Points (Vertices)
#define E3dGF_MATERIALS		0x0100				// Update Materials
#define E3dGF_REMAP_TEXTURES	(0x0100|E3dGF_TEXTURE_ST)	// Re-map textures
#define E3dGF_CALL_DESTROYPROCS	0x1000				// Don't call DestroyProcs...

#define E3dGF_ALL		0xFFFF

#define E3dGF_NORMALS		(E3dGF_VERTEX_NORMAL|E3dGF_POLYGON_NORMAL)

#define E3dGF_POINT_POSITION	(E3dGF_VERTEX_POSITION|E3dGF_CV_POSITION)
#define E3dGF_SHAPE		(E3dGF_VERTEX_POSITION|E3dGF_CV_POSITION|E3dGF_NORMALS)



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

#ifndef _E3dModel
#define _E3dModel
typedef struct E3dModel_S	E3dModel;		// Forward-define E3dModel
#endif

typedef struct E3dGeometryInfo_S	E3dGeometryInfo;

typedef int		(*E3dGeoEditProc)(E3dModel*, E3dGeometry*, E3dGeometryInfo*, int);
typedef int		(*E3dGeoProc)(E3dModel*, E3dGeometry*, E3dGeometryInfo*);

typedef struct
{
 char*		Name;
 unsigned int	StructSize;
 E3dGeoEditProc	EditProc;
 E3dGeoProc	DestroyProc;
 EResource*	Resources;	// Resource list
} E3dGeometryClass;


#define E3dGeometryInfoCore()\
 E3dGeometryClass*	Class


// General GeoInfo structure (these are the first fields in all GeoInfo structures)
//
struct E3dGeometryInfo_S
{
 E3dGeometryInfoCore();
};


typedef struct
{
 unsigned int	Reasons;
 E3dGeometry*	Geometry;
} E3dGeometryCallbackStruct;


typedef E3dGeometry*	(*E3dLODProc)(E3dGeometry*, E3dCoordinate);



// Fields of the generic Geometry structure (these are the first fields in all Geometry structures)
//
#define E3dGeometryCore()\
 int			GeoType;	/* Geometry type							*/\
 unsigned int		RefCnt;\
 unsigned int		LockCount;	/* E.g.: the Geometry is being modified...				*/\
 char*			Name;		/* Geometry name							*/\
 E3dModel**		Models;		/* Models that reference this Geometry					*/\
 unsigned int		NumOfModels;	/* # of Models that reference this Geometry				*/\
 unsigned int		NumOfInfoRecords;/* Number of type-specific info structures (e.g. torus radii, segments etc.)	*/\
 E3dGeometryInfo**	Info;		/* Type-specific info structures (e.g. torus radii, segments etc.)	*/\
 unsigned char		Selection;	/* Indicates if the Geometry is selected				*/\
 E3dLODProc		LODProc;	/* For procedural (e.g. continous LOD on a subdiv. Mesh) LOD		*/\
 E3dCoordinate		LODReference;	/* Level Of Detail "activation distance" for this Geometry		*/\
 int			LODStep;	/* Force displaying this LOD. 0: Original				*/\
 E3dGeometry**		LODs;		/* Levels of detail beyond this one					*/\
 unsigned int		NumOfLODs;\
 unsigned int		NumOfInputs;	/* For linking Items into a function-network				*/\
 E3dInterface**		Inputs;		/*	*/\
 unsigned int		NumOfOutputs;	/*	*/\
 E3dInterface**		Outputs;	/*	*/\
\
 EBool			AutoLOD;\
\
 EBool			Visible;\
\
 EBool			CastsShadows;\
 EBool			ReceivesShadows;\
\
 EBool			BBoxUptodate;	/*	*/\
 E3d3DPosition		BBoxMin,	/* Bounding box	*/\
			BBoxMax





// Generic Geometry structure
//
struct E3dGeometry_S
{
 E3dGeometryCore();
};




/*----------------------------------------------------------------------*/
/* Points-Geometry							*/
/*----------------------------------------------------------------------*/
typedef struct
{
 E3dCoordinate	X, Y, Z;
 unsigned long	Color;
 unsigned long	GLColor;
} E3dPoint;

typedef struct
{
// E3dGeometry part
//
 E3dGeometryCore();

// E3dPoints part
//
 unsigned int		NumOfPoints;
 E3dPoint*		Points;
} E3dPoints;




/*--------------------------------------------------------------*/
/* Function prototypes						*/
/*--------------------------------------------------------------*/
extern E3dGeometryClass*	E3d_GeometryClassFindByName(char* LName);
extern E3dGeometryClass*	E3d_GeometryClassRegister(E3dGeometryClass* LClassTemplate);
extern void			E3d_GeometryClassRemove(E3dGeometryClass* LClass);
extern void			E3d_GeometryClassDeactivate(E3dGeometryClass* LClass);

extern int			E3d_GeometryInfoRemove(E3dGeometry* LGeometry, E3dGeometryInfo* LInfo);
extern int			E3d_GeometryInfoRemoveAll(E3dGeometry* LGeometry);
extern E3dGeometryInfo*		E3d_GeometryInfoAdd(E3dGeometry* LGeometry, E3dGeometryClass* LClass);
extern E3dGeometryInfo*		E3d_GeometryInfoByClass(E3dGeometry* LGeometry, E3dGeometryClass* LClass);
extern int			E3d_GeometryInfoCallDestroyProcs(E3dGeometry* LGeometry);


extern void		E3d_GeometryFree(E3dGeometry* LGeometry);
extern E3dGeometry*	E3d_GeometryClone(E3dGeometry* LGeometry, int LFlags);

extern void		E3d_GeometryTransform(E3dGeometry* LGeometry, E3dMatrix LMatrix, E3dMatrix LNormalMatrix);

extern EBool		E3d_GeometryGetBoundingBox(E3dGeometry* LGeometry, E3d3DPosition* LBBMin, E3d3DPosition* E3d3DPosition, unsigned int LWhatToInclude);
extern EBool		E3d_GeometryGetTransformedBoundingBox(E3dGeometry* LGeometry, E3dMatrix LMatrix, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);
extern EBool		E3d_GeometryGetPerspectiveProjectedBoundingBox(E3dGeometry* LGeometry, E3dMatrix LMatrix, E3d2DPosition* LBBMin, E3d2DPosition* LBBMax, E3dHPosition* LMaxProjectedXYAbsValPoint, unsigned int LWhatToInclude);

extern int		E3d_GeometryMap2DTextures(E3dGeometry* LGeometry);


extern EBool		E3d_GeometryAddOutput(E3dGeometry* LGeometry, E3dInterface* LOutput);
extern EBool		E3d_GeometryRemoveOutput(E3dGeometry* LGeometry, E3dInterface* LOutput);

extern E3dPoint*	E3d_PointsAllocate(unsigned int LNumOfPoints);
extern E3dPoints*	E3d_PointsGeomAllocate(void);
extern void		E3d_PointsFree(E3dPoints* LPoints);

extern void		E3d_GeometryUpdateForDisplay(E3dGeometry* LGeometry, unsigned int LReasons);
extern void		E3d_GeometryFreeRenderData(E3dGeometry* LGeometry);

extern int		E3d_GeometryRemoveFromModels(E3dGeometry* LGeometry);

extern void		E3d_GeometryToggleSelection(E3dGeometry* LGeometry, EBool LUnselectTheRest);

extern void		E3d_GeometryModelsSetSelection(E3dGeometry* LGeometry, int LSelection);


extern EBool		E3d_GeometryTesselate(E3dGeometry* LGeometry, EBool LDoConvex);

extern void		E3d_GeometryAddLock(E3dGeometry* LGeometry);
extern void		E3d_GeometryDelLock(E3dGeometry* LGeometry);



#ifdef USEOpenGL
extern void		E3d_GeometryRemoveGLDisplayLists(E3dGeometry* LGeometry);
#endif // USEOpenGL



/*------------------------------------------------------------------------------*/
/* Macros									*/
/*------------------------------------------------------------------------------*/


/*----------------------------------------------------------------------*/
/* Template functions							*/
/*----------------------------------------------------------------------*/

//================================================================================
// Activation callback template for a Geometry with construction-history
//================================================================================
#define E3dTpl_ACB_CHist(mType, mPrefix)\
 {\
  EBool	mSuccess;\
\
  if(mPrefix##MainGeometry) return;\
\
  mSuccess=FALSE;\
  if((mPrefix##Model=mPrefix##Get(NULL, NULL, &mPrefix##Info, E3dGF_ALL))!=NULL)\
  {\
   mPrefix##MainGeometry=mPrefix##Geometry=mPrefix##Model->Geometries[0];\
   mPrefix##MainGeometry->LockCount=1;\
   mPrefix##MainGeometry->AutoLOD=FALSE;\
   mSuccess=E3d_SceneAddModelHrc(E3d_Scene, mPrefix##Model);\
   E3dp_SceneLayoutOnSchematics(E3d_Scene);\
  }\
\
  mPrefix##CreateMode=TRUE;\
  if(mSuccess)\
  {\
   mType##Info*	LInfo=(mType##Info*)E3d_GeometryInfoByClass(mPrefix##MainGeometry, mPrefix##Info.Class);\
\
   if(((EguiPushButtonCallbackStruct*)LCallData)->Reason==ECR_OPTIONS) mPrefix##PopupDialog(LInfo);\
   else\
   {\
    mPrefix##MainGeometry->LockCount-=1;\
    if(mPrefix##MainGeometry->LockCount==0) E3d_GeometryUpdateForDisplay(mPrefix##MainGeometry, E3dGF_LOCKUNLOCK);\
    _Plugin->LockCount-=1;mPrefix##Model=NULL;mPrefix##MainGeometry=NULL;mPrefix##Geometry=NULL;\
   }\
   E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
  }\
 }


/*==============================================================================*/
/* Geometry done editing							*/
/*==============================================================================*/
#define E3dTpl_GeoDoneEditing(mPrefix)\
{\
 mPrefix##Geometry->LockCount-=1;if(mPrefix##Geometry->LockCount==0) E3d_GeometryUpdateForDisplay(mPrefix##Geometry, E3dGF_LOCKUNLOCK);\
 mPrefix##MainGeometry->AutoLOD=TRUE;\
 mPrefix##Model=NULL;mPrefix##MainGeometry=mPrefix##Geometry=NULL;\
}


/*==============================================================================*/
/* Finish editing a Geometry (dialog "Ok" button)				*/
/*==============================================================================*/
#define E3dTpl_GeoOK(mPrefix)\
{\
 E3dTpl_GeoDoneEditing(mPrefix);\
 EGUI_UndisplayShell(mPrefix##Dialog);_Plugin->LockCount-=1;\
 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
}


/*==============================================================================*/
/* Add new instance of a Geometry (dialog "New" button)				*/
/*==============================================================================*/
#define E3dTpl_GeoADD(mPrefix)\
{\
 E3dTpl_GeoDoneEditing(mPrefix);\
\
 mPrefix##CreateMode=TRUE;\
\
 if((mPrefix##Model=mPrefix##Get(NULL, NULL, &mPrefix##Info, E3dGF_ALL))!=NULL)\
 {\
  mPrefix##MainGeometry=mPrefix##Geometry=mPrefix##Model->Geometries[0];\
  mPrefix##MainGeometry->AutoLOD=FALSE;\
  E3d_SceneAddModelHrc(E3d_Scene, mPrefix##Model);\
  E3dp_SceneLayoutOnSchematics(E3d_Scene);\
 }\
 mPrefix##UpdateDialog(&mPrefix##Info);\
 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
}


//================================================================================
// Finish editing a Geometry and remove it (dialog "Cancel" button)
//================================================================================
#define E3dTpl_GeoCANCEL(mPrefix)\
{\
 mPrefix##Geometry->LockCount-=1;\
 if(mPrefix##Geometry->LockCount==0)\
 {\
  if(mPrefix##CreateMode) { E3d_SceneRemoveModelHrc(E3d_Scene, mPrefix##Model);E3d_ModelHrcFree(mPrefix##Model, TRUE); }\
  else\
  {\
   E3d_GeometryUpdateForDisplay(mPrefix##Geometry, E3dGF_LOCKUNLOCK);\
   mPrefix##MainGeometry->AutoLOD=TRUE;\
  }\
 }\
 mPrefix##Model=NULL;mPrefix##MainGeometry=mPrefix##Geometry=NULL;\
\
 EGUI_UndisplayShell(mPrefix##Dialog);_Plugin->LockCount-=1;\
 E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
}


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


//================================================================================
// EditProc template for a Geometry with a simple, self-contained
// construction-history (no inputs) (Box, Grid, Torus etc.) and Level Of Detail
//================================================================================
#define E3dTplEditProc_LODCHist(mType, mPrefix)\
{\
/* If LInfo is NULL, add a new Info record to the Geometry	*/\
 if(LInfo==NULL)\
 {\
  LInfo=E3d_GeometryInfoAdd(LGeometry, mPrefix##Info.Class);\
  memcpy(LInfo, &mPrefix##Info, sizeof(mType##Info));\
  return(E3dEDITP_INFO_ADDED);\
 }\
 else\
 {\
  E3dGeometry*	mLOD=LGeometry;\
\
  if(LLODIndex) mLOD=LGeometry->LODs[LLODIndex-1];\
\
/* If the same LOD of the same Geometry is still being edited, return	*/\
/**/\
  if((mPrefix##MainGeometry==LGeometry)&&(mPrefix##Geometry==mLOD)) return(E3dEDITP_IN_USE);\
\
  mPrefix##CreateMode=FALSE;\
\
  if(mPrefix##MainGeometry)\
  {\
   mPrefix##Geometry=mLOD;\
   mPrefix##Geometry->LockCount-=1;		/* Unlock currently edited Geometry	*/\
   if(mPrefix##Geometry->LockCount==0) E3d_GeometryUpdateForDisplay(mPrefix##Geometry, E3dGF_LOCKUNLOCK);\
\
/* _PopupDialog will increment this, but the dialog is already up...	*/\
\
   _Plugin->LockCount-=1;\
  }\
\
  mPrefix##Model=LModel;mPrefix##MainGeometry=LGeometry;mPrefix##Geometry=mLOD;\
  mPrefix##MainGeometry->AutoLOD=FALSE;\
  mLOD->LockCount+=1;if(mLOD->LockCount==1) E3d_GeometryUpdateForDisplay(mLOD, E3dGF_LOCKUNLOCK);\
  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
\
  mPrefix##PopupDialog((mType##Info*)(LInfo));\
  return(E3dEDITP_EDITING);\
 }\
}


/*======================================================================================================*/
/* EditProc template for a Geometry with construction-history with input(s) (Extrude, Revolve etc.)	*/
/*======================================================================================================*/
#define E3dTplEditProc_LODCHistInput(mType, mPrefix)\
{\
/* If LInfo is NULL, add a new Info record to the Geometry	*/\
\
 if(LInfo==NULL)\
 {\
  mType##Info*	mInfo;\
\
  LInfo=E3d_GeometryInfoAdd(LGeometry, mPrefix##Info.Class);\
  memcpy(LInfo, &mPrefix##Info, sizeof(mType##Info));\
\
  mInfo=(mType##Info*)LInfo;\
  mInfo->Model=LModel;\
  mInfo->Geometry=LGeometry;\
\
  mInfo->InputNode.ClientData=(EPointer)LInfo;\
\
  return(E3dEDITP_INFO_ADDED);\
 }\
 else\
 {\
  E3dGeometry*	mLOD=LGeometry;\
\
  if(LLODIndex) mLOD=LGeometry->LODs[LLODIndex-1];\
\
/* If the same LOD of the same Geometry is still being edited, return	*/\
/**/\
  if((mPrefix##MainGeometry==LGeometry)&&(mPrefix##Geometry==mLOD)) return(E3dEDITP_IN_USE);\
\
  mPrefix##CreateMode=FALSE;\
\
  if(mPrefix##MainGeometry)\
  {\
   mPrefix##Geometry=mLOD;\
   mPrefix##Geometry->LockCount-=1;		/* Unlock currently edited Geometry	*/\
   if(mPrefix##Geometry->LockCount==0) E3d_GeometryUpdateForDisplay(mPrefix##Geometry, E3dGF_LOCKUNLOCK);\
\
/* _PopupDialog will increment this, but the dialog is already up...	*/\
/**/\
   _Plugin->LockCount-=1;\
  }\
\
  mPrefix##Model=LModel;mPrefix##MainGeometry=LGeometry;mPrefix##Geometry=mLOD;\
  mPrefix##MainGeometry->AutoLOD=FALSE;\
  mLOD->LockCount+=1;if(mLOD->LockCount==1) E3d_GeometryUpdateForDisplay(mLOD, E3dGF_LOCKUNLOCK);\
  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);\
\
  mPrefix##PopupDialog((mType##Info*)(LInfo));\
  return(E3dEDITP_EDITING);\
 }\
}


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

#endif	// _E3DGeometry_h
