/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Selecting								*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Dec-09 23:34:01					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#include <float.h>
#include <math.h>
#include <stdio.h>

#include <E3D/E3D.h>

#ifndef _E3DFace_h
#include <E3D/Face.h>
#endif

#ifndef _E3DModel_h
#include <E3D/Model.h>
#endif

#ifndef _E3DPick_h
#include <E3D/Pick.h>
#endif

#ifndef _E3DScene_h
#include <E3D/Scene.h>
#endif

#ifndef _E3DSelect_h
#include <E3D/Select.h>
#endif


/*======================================================================*/
/* Unselect SubGeometries of a Geometry (e.g. PolyGroups of a Mesh)	*/
/*======================================================================*/
void E3d_GeometryUnselectSubGeometries(E3dGeometry* LGeometry)
{
 switch(LGeometry->GeoType)
 {
  caseE3dMESH():
   {
    E3dMesh*		LMesh=(E3dMesh*)LGeometry;
    E3dPolyGroup*	LPolyGroup;
    E3dPolyGroup**	LPolyGroups=LMesh->PolyGroups;
    unsigned int	LGCnt, LGNum=LMesh->NumOfPolyGroups;


    for(LGCnt=0;LGCnt<LGNum;LGCnt++)
    {
     LPolyGroup=LPolyGroups[LGCnt];LPolyGroup->Selected=FALSE;
    }
   }
  break;

  case E3dGEO_SPLINE:
   {
    E3dSpline*		LSpline=(E3dSpline*)LGeometry;
    unsigned int	LC, LN=LSpline->NumOfCVs;


    switch(LSpline->SplineType)
    {
     case E3dSPL_BEZIER:
      {
       E3dBezierCV*	LCV=(E3dBezierCV*)(LSpline->CVs);

       for(LC=0;LC<LN;LC++, LCV++) LCV->Flags&=0;
      }
     break;

     default:
      {
       E3dSplineCV*	LCV=(E3dSplineCV*)(LSpline->CVs);

       for(LC=0;LC<LN;LC++, LCV++) LCV->Flags&=0;
      }
     break;
    }
   }
  break;
 }
}


/*==============================================*/
/* Select a Model (and its Geometries)		*/
/*==============================================*/
void E3d_SelectModelGeometries(E3dModel* LModel)
{
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 unsigned int	LGmC, LGmN;


 LGeometries=LModel->Geometries;
 LGmN=LModel->NumOfGeometries;
 for(LGmC=0;LGmC<LGmN;LGmC++)
 {
  LGeometry=LGeometries[LGmC];
  LGeometry->Selection=E3dGSEL_GEOMETRY;
 }
}


/*==============================================*/
/* Unselect the Geometries of a Model node	*/
/*==============================================*/
void E3d_UnselectModelGeometries(E3dModel* LModel, E3dGeometry* LSkipThisGeometry, int LFlags)
{
 E3dGeometry**	LGeometries;
 E3dGeometry*	LGeometry;
 unsigned int	LGmC, LGmN;


 LGeometries=LModel->Geometries;
 LGmN=LModel->NumOfGeometries;
 for(LGmC=0;LGmC<LGmN;LGmC++)
 {
  LGeometry=LGeometries[LGmC];
  if(LGeometry!=LSkipThisGeometry)
  {
   if(LFlags&E3dSF_GEOMETRIES) LGeometry->Selection=E3dSEL_NONE;

   switch(LGeometry->GeoType)
   {
    caseE3dMESH():
     {
      E3dMesh*		LMesh=(E3dMesh*)LGeometry;
      E3dPolyGroup**	LPolyGroups;
      E3dPolyGroup*	LPolyGroup;
      unsigned int	LGCnt, LGNum;


      if(LFlags&E3dSF_VERTICES)
      {
       E3dVertex*	LVertex=LMesh->Vertices;
       unsigned int	LVC=LMesh->NumOfVertices;


       if(LVC)
       {
	do
	{
	 LVertex->Flags&=(E3dVTXF_ALL-E3dVTXF_TAGGED-E3dVTXF_ACTIVE);
	 LVertex++;
	} while(--LVC);
       }
      }

      LGNum=LMesh->NumOfPolyGroups;LPolyGroups=LMesh->PolyGroups;
      for(LGCnt=0;LGCnt<LGNum;LGCnt++)
      {
       LPolyGroup=LPolyGroups[LGCnt];
       if(LFlags&E3dSF_POLYGROUPS) LPolyGroup->Selected=FALSE;

       if(LFlags&E3dSF_POLYGONS)
       {
	E3dPolygon*	LPolygon=LPolyGroup->Polygons;
	unsigned int	LPC=LPolyGroup->NumOfPolygons;


	if(LPC)
	{
	 do
	 {
	  LPolygon->Flags&=(E3dPolyFlagALL-E3dPolyFlagSELECTED);
	  LPolygon++;
	 } while(--LPC);
	}
       }
      }
     }
    break;

    case E3dGEO_SPLINE:
     E3d_SplineUnselect((E3dSpline*)LGeometry, LFlags);
    break;

    case E3dGEO_FACE:
     {
      E3dFace*		LFace=(E3dFace*)LGeometry;
      unsigned int	LHC, LHN=LFace->NumOfHoles;

      E3d_SplineUnselect(LFace->Exterior, LFlags);
      for(LHC=0;LHC<LHN;LHC++) E3d_SplineUnselect(LFace->Holes[LHC], LFlags);
     }
    break;
   }
  }
 }
}


/*======================================================*/
/* Invert the SELECTED flag of the given Polygon	*/
/*======================================================*/
E3dPolygon* E3d_SelectTogglePolygonSelection(E3dModel* LModel, E3dGeometry* LGeometry, E3dPolyGroup* LPolyGroup, E3dPolygon* LPolygon, EBool LUnselectTheRest)
{
 switch(LModel->Selection)
 {
  case E3dSEL_NONE:
  return(NULL);

  case E3dSEL_GEOMETRY:
   if((LGeometry->Selection==E3dGSEL_GEOMETRY)||((LGeometry->Selection==E3dGSEL_POLYGROUP)&&(LPolyGroup->Selected)))
   {
    LPolygon->Flags^=E3dPolyFlagSELECTED;
#ifdef USEOpenGL
    E3d_GeometryRemoveGLDisplayLists(LGeometry);
#endif // USEOpenGL
    return(LPolygon);
   }
  break;

  default:
   LPolygon->Flags^=E3dPolyFlagSELECTED;
#ifdef USEOpenGL
   E3d_GeometryRemoveGLDisplayLists(LGeometry);
#endif // USEOpenGL
   return(LPolygon);
 }
 return(NULL);
}


/*==============================================*/
/* Select the given Mesh and PolyGroup		*/
/*==============================================*/
void E3d_SelectMeshPolyGroup(E3dMesh* LMesh, E3dPolyGroup* LPolyGroup, EBool LUnselectTheRest)
{
 int		LCnt;

 if((LMesh->Selection==E3dGSEL_POLYGROUP)&&(LPolyGroup->Selected))
 {
  LMesh->Selection=E3dGSEL_NONE;LPolyGroup->Selected=FALSE;

  E3d_GeometryModelsSetSelection((E3dGeometry*)LMesh, E3dSEL_NONE);

#ifdef USEOpenGL
  E3d_GeometryRemoveGLDisplayLists((E3dGeometry*)LMesh);
#endif // USEOpenGL
 }
 else
 {
  LMesh->Selection=E3dGSEL_POLYGROUP;LPolyGroup->Selected=TRUE;
  if(LUnselectTheRest)
  {
   E3dModel**		LRootModels;
   E3dModel*		LModel;
   E3dGeometry**	LGeometries;
   E3dGeometry*		LGeometry;
   E3dMesh*		LTMesh;
   E3dPolyGroup**	LPolyGroups;
   unsigned int		LGmC, LGmN, LGCnt, LGNum, LRN;


// Unselect the other PolyGroups of LMesh
//
   LGNum=LMesh->NumOfPolyGroups;LPolyGroups=LMesh->PolyGroups;
   for(LGCnt=0;LGCnt<LGNum;LGCnt++) { if(LPolyGroups[LGCnt]!=LPolyGroup) LPolyGroups[LGCnt]->Selected=FALSE; }

// Unselect the Geometries other than LMesh in the Scene
//
   LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
   for(LCnt=0;LCnt<LRN;LCnt++)
   {
    for(LModel=LRootModels[LCnt];LModel;LModel=LModel->Next)
    {
     LModel->Selection=E3dSEL_NONE;
     LGeometries=LModel->Geometries;
     LGmN=LModel->NumOfGeometries;
     for(LGmC=0;LGmC<LGmN;LGmC++)
     {
      LGeometry=LGeometries[LGmC];

      switch(LGeometry->GeoType)
      {
       caseE3dMESH():
	LTMesh=(E3dMesh*)LGeometry;

	if(LTMesh!=LMesh)
	{
	 LTMesh->Selection=E3dGSEL_NONE;

	 LGNum=LTMesh->NumOfPolyGroups;LPolyGroups=LTMesh->PolyGroups;
	 for(LGCnt=0;LGCnt<LGNum;LGCnt++) LPolyGroups[LGCnt]->Selected=FALSE;
	}
       break;

       default:
	E3d_GeometryUnselectSubGeometries(LGeometry);
	LGeometry->Selection=E3dGSEL_NONE;
       break;
      }

#ifdef USEOpenGL
      E3d_GeometryRemoveGLDisplayLists(LGeometry);
#endif // USEOpenGL
     }
    }
   }
  }
  E3d_GeometryModelsSetSelection((E3dGeometry*)LMesh, E3dSEL_GEOMETRY);
 }
}


/*==============================================================*/
/* Select the whole hierarchy that contains the given Model	*/
/*==============================================================*/
E3dModel* E3d_SelectModelTree(E3dModel* LModel, EBool LUnselectTheRest)
{
 register E3dModel*	LRootModel;
 register E3dModel*	LCurrentModel;
 E3dModel*		LNewActiveModel=NULL;

// Get hierarchy root
//
 for(LRootModel=LModel;LRootModel->Parent;) LRootModel=LRootModel->Parent;

 LNewActiveModel=LRootModel;
 LRootModel->Selection=E3dSEL_BRANCH_ROOT;E3d_UnselectModelGeometries(LRootModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LRootModel);
#endif // USEOpenGL

 for(LCurrentModel=LRootModel->Next;LCurrentModel;LCurrentModel=LCurrentModel->Next)
 {
  LCurrentModel->Selection=E3dSEL_BRANCH;E3d_UnselectModelGeometries(LCurrentModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LCurrentModel);
#endif // USEOpenGL
 }

 if(LUnselectTheRest)
 {
  E3dModel**	LRootModels;
  unsigned int	LCnt, LRN=E3d_Scene->NumOfRootModels;


  LRootModels=E3d_Scene->RootModels;
  for(LCnt=0;LCnt<LRN;LCnt++)
  {
   LCurrentModel=LRootModels[LCnt];
   if(LCurrentModel!=LRootModel)
   {
    for(;LCurrentModel;LCurrentModel=LCurrentModel->Next)
    {
     LCurrentModel->Selection=E3dSEL_NONE;E3d_UnselectModelGeometries(LCurrentModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
     E3d_ModelRemoveGLDisplayLists(LCurrentModel);
#endif // USEOpenGL
    }
   }
  }
 }
 return(LNewActiveModel);
}


/*======================================================*/
/* Select the branch rooted by the given Model		*/
/*======================================================*/
E3dModel* E3d_SelectModelBranch(E3dModel* LBranchRootModel, EBool LUnselectTheRest)
{
 E3dModel*		LModel;
 E3dModel*		LNextBranchModel;
 E3dModel*		LNewActiveModel=NULL;
 int			LCnt;


 LNewActiveModel=LBranchRootModel;
 LBranchRootModel->Selection=E3dSEL_BRANCH_ROOT;E3d_UnselectModelGeometries(LBranchRootModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
 E3d_ModelRemoveGLDisplayLists(LBranchRootModel);
#endif // USEOpenGL

 LNextBranchModel=E3d_ModelHrcBranchGetNodeAfter(LBranchRootModel);
 for(LModel=LBranchRootModel->Next;LModel!=LNextBranchModel;LModel=LModel->Next)
 {
  LModel->Selection=E3dSEL_BRANCH;E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
 }

 if(LUnselectTheRest)
 {
  E3dModel**		LRootModels=E3d_Scene->RootModels;
  E3dModel*		LRootModel;
  register int		LRN=E3d_Scene->NumOfRootModels;

  for(LRootModel=LBranchRootModel;LRootModel->Parent;)	// Go upward to find the given model's root
  {
   LRootModel=LRootModel->Parent;
  }

  for(LCnt=0;LCnt<LRN;LCnt++)
  {
   if((LModel=LRootModels[LCnt])!=LRootModel)
   {
    for(;LModel;LModel=LModel->Next)
    {
     LModel->Selection=E3dSEL_NONE;E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
     E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
    }
   }
  }
 }
 return(LNewActiveModel);
}


/*==============================================*/
/* Select the given Model			*/
/*==============================================*/
E3dModel* E3d_ModelNodeToggleSelection(E3dModel* LModel, EBool LUnselectTheRest)
{
 E3dModel**	LRootModels;
 E3dModel*	LCurrentModel;
 int		LCnt, LRN;

 E3d_UnselectModelGeometries(LModel, NULL, E3dSF_GEOMETRIES);
 if(LModel->Selection==E3dSEL_NODE)
 {
  LModel->Selection=E3dSEL_NONE;
  E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
 }
 else
 {
  LModel->Selection=E3dSEL_NODE;
#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL

  if(LUnselectTheRest)
  {
   LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
   for(LCnt=0;LCnt<LRN;LCnt++)
   {
    for(LCurrentModel=LRootModels[LCnt];LCurrentModel;LCurrentModel=LCurrentModel->Next)
    {
     if(LCurrentModel!=LModel)
     {
      LCurrentModel->Selection=E3dSEL_NONE;
      E3d_UnselectModelGeometries(LCurrentModel, NULL, E3dSF_ALL);
     }
    }
   }
  }
  return(LModel);
 }
 return(NULL);
}


/*======================================================*/
/* Select the given node and all of its descendants	*/
/*======================================================*/
E3dModel* E3d_ModelBranchToggleSelection(E3dModel* LModel, EBool LUnselectTheRest)
{
 register char		LSelection, LSelectionType=E3dSEL_NONE;
 register int		LCnt, LRN;
 register E3dModel*	LCurrentModel;
 E3dModel*		LNewActiveModel=NULL;

 LSelection=LModel->Selection;
 switch(LSelection)
 {
  case E3dSEL_NONE:
  case E3dSEL_NODE:
  case E3dSEL_BRANCH:
  case E3dSEL_GEOMETRY:
   if(LUnselectTheRest)
   {
    LRN=E3d_Scene->NumOfRootModels;
    for(LCnt=0;LCnt<LRN;LCnt++)
    {
     LCurrentModel=E3d_Scene->RootModels[LCnt];
     for(;LCurrentModel;LCurrentModel=LCurrentModel->Next)
     {
      if(LCurrentModel!=LModel)
      {
       LCurrentModel->Selection=E3dSEL_NONE;E3d_UnselectModelGeometries(LCurrentModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
       E3d_ModelRemoveGLDisplayLists(LCurrentModel);
#endif // USEOpenGL
      }
     }
    }
   }
   LModel->Selection=E3dSEL_BRANCH_ROOT;
   LSelectionType=E3dSEL_BRANCH;
#ifdef USEOpenGL
   E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
   LNewActiveModel=LModel;
  break;

  case E3dSEL_BRANCH_ROOT:
   LModel->Selection=E3dSEL_NONE;E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
   LSelectionType=E3dSEL_NONE;
#ifdef USEOpenGL
   E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
   LNewActiveModel=NULL;
  break;
 }

// Walk the branch and set the SelectionType
//
 LCurrentModel=LModel->Child;
 while(LCurrentModel)
 {
  E3d_UnselectModelGeometries(LCurrentModel, NULL, E3dSF_ALL);

  LCurrentModel->Selection=LSelectionType;

#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LCurrentModel);
#endif // USEOpenGL


  if(LCurrentModel->Child) LCurrentModel=LCurrentModel->Child;			// Does the current model have a child ? (1)
										// (1Y) Yes, let the child be the next...
  else										// (1N) No, does it have a sibling ? (2)
  {
   if(LCurrentModel->NextSibling) LCurrentModel=LCurrentModel->NextSibling;	// (2Y) Yes, let the sibling be the next...
   else										// (2N) No, go back upward in this branch until
   {										// we find a model that has a sibling
    while((LCurrentModel->NextSibling==NULL)&&(LCurrentModel->Parent!=NULL))
    {
     LCurrentModel=LCurrentModel->Parent;
     if(LCurrentModel==LModel) { LCurrentModel=NULL;break; }
    }
    if(LCurrentModel) LCurrentModel=LCurrentModel->NextSibling;
   }
  }
 }
 return(LNewActiveModel);
}


/*======================================================================*/
/* Select/unselect the whole hierarchy that contains the given Model	*/
/*======================================================================*/
E3dModel* E3d_ModelTreeToggleSelection(E3dModel* LInModel, EBool LUnselectTheRest)
{
 register E3dModel*	LModel;
 E3dModel*		LRootModel;
 E3dModel*		LNewActiveModel=NULL;
 unsigned int		LCnt, LRN;


 LRootModel=LInModel;

 while(LRootModel->Parent) LRootModel=LRootModel->Parent;

 for(LModel=LRootModel;LModel;LModel=LModel->Next) E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);

 if(LRootModel->Selection==E3dSEL_BRANCH_ROOT)
 {
  for(LModel=LRootModel;LModel;LModel=LModel->Next)
  {
   LModel->Selection=E3dSEL_NONE;
#ifdef USEOpenGL
   E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
  }
  LNewActiveModel=NULL;
 }
 else
 {
  LNewActiveModel=LRootModel;
  LRootModel->Selection=E3dSEL_BRANCH_ROOT;

#ifdef USEOpenGL
  E3d_ModelRemoveGLDisplayLists(LRootModel);
#endif // USEOpenGL

  for(LModel=LRootModel->Child;LModel;LModel=LModel->Next)
  {
   LModel->Selection=E3dSEL_BRANCH;
#ifdef USEOpenGL
   E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
  }

  if(LUnselectTheRest)
  {
   LRN=E3d_Scene->NumOfRootModels;
   for(LCnt=0;LCnt<LRN;LCnt++)
   {
    if((LModel=E3d_Scene->RootModels[LCnt])!=LRootModel)
    {
     for(;LModel;LModel=LModel->Next)
     {
      LModel->Selection=E3dSEL_NONE;E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
#ifdef USEOpenGL
      E3d_ModelRemoveGLDisplayLists(LModel);
#endif // USEOpenGL
     }
    }
   }
  }
 }
 return(LNewActiveModel);
}



/*==============================================*/
/* Select/unselect a Spline segment		*/
/*==============================================*/
EBool E3d_SplineSegmentToggleSelection(E3dSpline* LSpline, unsigned int LSegment, EBool LUnselectTheRest)
{
 unsigned int	LC, LN=LSpline->NumOfCVs;
 EBool		LSet=FALSE;

 switch(LSpline->SplineType)
 {
  case E3dSPL_BEZIER:
   {
    E3dBezierCV*	LBezierCVs=(E3dBezierCV*)(LSpline->CVs);
    E3dBezierCV*	LBezierCV=LBezierCVs+LSegment;

    if(LBezierCV->Flags&E3dKEYF_SEGMENT_SELECTED) LSet=FALSE;
    else LSet=TRUE;

    if(LUnselectTheRest)
    {
     unsigned int	LRN;
     E3dModel*		LModel;
     E3dModel**		LRootModels;

// Unselect all other Models and their Geometries
//
     LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
     for(LC=0;LC<LRN;LC++)
     {
      for(LModel=LRootModels[LC];LModel;LModel=LModel->Next)
      {
       LModel->Selection=E3dSEL_NONE;
       E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
      }
     }
    }

    if(LSet) LBezierCV->Flags|=E3dKEYF_ACTIVE|E3dKEYF_SEGMENT_SELECTED;

// If there's a segment selected, set LSpline->Selection to E3dGSEL_SPLINE_SEGMENT
//
    LBezierCV=(E3dBezierCV*)(LSpline->CVs);
    for(LC=0;LC<LN;LC++, LBezierCV++)
    {
     if(LBezierCV->Flags&E3dKEYF_SEGMENT_SELECTED)
     {
      LSpline->Selection=E3dGSEL_SPLINE_SEGMENT;

      E3d_GeometryModelsSetSelection((E3dGeometry*)LSpline, E3dSEL_GEOMETRY);

      return(LSet);
     }
    }
    LSpline->Selection=E3dGSEL_NONE;
   }
  break;

  case E3dSPL_BSPLINE:
  case E3dSPL_CARDINAL:
   {
    E3dSplineCV*	LSplineCVs=(E3dSplineCV*)(LSpline->CVs);
    E3dSplineCV*	LSplineCV=LSplineCVs+LSegment;

    if(LSplineCV->Flags&E3dKEYF_SEGMENT_SELECTED) LSet=FALSE;
    else LSet=TRUE;

    if(LUnselectTheRest)
    {
     unsigned int	LRN;
     E3dModel*		LModel;
     E3dModel**		LRootModels;

// Unselect all other Models and their Geometries
//
     LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
     for(LC=0;LC<LRN;LC++)
     {
      for(LModel=LRootModels[LC];LModel;LModel=LModel->Next)
      {
       LModel->Selection=E3dSEL_NONE;
       E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
      }
     }
    }

    if(LSet) LSplineCV->Flags|=E3dKEYF_ACTIVE|E3dKEYF_SEGMENT_SELECTED;

// If there's a segment selected, set LSpline->Selection to E3dGSEL_SPLINE_SEGMENT
//
    LSplineCV=(E3dSplineCV*)(LSpline->CVs);
    for(LC=0;LC<LN;LC++, LSplineCV++)
    {
     if(LSplineCV->Flags&E3dKEYF_SEGMENT_SELECTED)
     {
      LSpline->Selection=E3dGSEL_SPLINE_SEGMENT;

      E3d_GeometryModelsSetSelection((E3dGeometry*)LSpline, E3dSEL_GEOMETRY);

      return(LSet);
     }
    }
    LSpline->Selection=E3dGSEL_NONE;
   }
  break;

  default:
   {
    E3dSplineCV*	LSplineCVs=(E3dSplineCV*)(LSpline->CVs);
    E3dSplineCV*	LSplineCV=LSplineCVs+LSegment;

    if(LSplineCV->Flags&E3dKEYF_SEGMENT_SELECTED) LSet=FALSE;
    else LSet=TRUE;


    if(LUnselectTheRest)
    {
     unsigned int	LRN;
     E3dModel*		LModel;
     E3dModel**		LRootModels;

// Unselect all other Models and their Geometries
//
     LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
     for(LC=0;LC<LRN;LC++)
     {
      for(LModel=LRootModels[LC];LModel;LModel=LModel->Next)
      {
       LModel->Selection=E3dSEL_NONE;
       E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
      }
     }
    }

    if(LSet) LSplineCV->Flags|=E3dKEYF_ACTIVE|E3dKEYF_SEGMENT_SELECTED;

// If there's a segment selected, set LSpline->Selection to E3dGSEL_SPLINE_SEGMENT
//
    LSplineCV=(E3dSplineCV*)(LSpline->CVs);
    for(LC=0;LC<LN;LC++, LSplineCV++)
    {
     if(LSplineCV->Flags&E3dKEYF_SEGMENT_SELECTED)
     {
      LSpline->Selection=E3dGSEL_SPLINE_SEGMENT;

      E3d_GeometryModelsSetSelection((E3dGeometry*)LSpline, E3dSEL_GEOMETRY);

      return(LSet);
     }
    }
    LSpline->Selection=E3dGSEL_NONE;
   }
  break;
 }

 return(LSet); 
}


/*==============================================*/
/* Select/unselect a Contour Spline of a Face	*/
/*==============================================*/
EBool E3d_FaceContourToggleSelection(E3dFace* LFace, int LContourIndex, E3dSpline* LSpline, EBool LUnselectTheRest)
{
 unsigned int	LC, LN=LSpline->NumOfCVs;
 EBool		LSet=FALSE;


 if(LSpline->Selection==E3dGSEL_GEOMETRY) LSet=FALSE;
 else LSet=TRUE;

 if(LUnselectTheRest)
 {
  E3dModel*	LModel;
  E3dModel**	LRootModels;
  unsigned int	LRN;


// Unselect all other Models and their Geometries
//
  LRN=E3d_Scene->NumOfRootModels;LRootModels=E3d_Scene->RootModels;
  for(LC=0;LC<LRN;LC++)
  {
   for(LModel=LRootModels[LC];LModel;LModel=LModel->Next)
   {
    LModel->Selection=E3dSEL_NONE;
    E3d_UnselectModelGeometries(LModel, NULL, E3dSF_ALL);
   }
  }
 }

 if(LSet) LSpline->Selection=E3dGSEL_GEOMETRY;

// If there's a Contour selected, set LFace->Selection to E3dGSEL_FACE_CONTOUR
//
 if(LFace->Exterior->Selection!=E3dGSEL_NONE)
 {
  LFace->Selection=E3dGSEL_FACE_CONTOUR;
  E3d_GeometryModelsSetSelection((E3dGeometry*)LFace, E3dSEL_GEOMETRY);
  return(LSet);
 }
 LN=LFace->NumOfHoles;
 for(LC=0;LC<LN;LC++)
 {
  if(LFace->Holes[LC]->Selection!=E3dGSEL_NONE)
  {
   LFace->Selection=E3dGSEL_FACE_CONTOUR;
   E3d_GeometryModelsSetSelection((E3dGeometry*)LFace, E3dSEL_GEOMETRY);
   return(LSet);
  }
 }

 return(LSet); 
}
