/*======================================================================================================*/
/* Information on selection										*/
/*													*/
/* Plugin for EQUINOX-3D										*/
/*													*/
/* AUTHOR:	Gabor Nagy										*/
/* DATE:	1996-Dec-09 23:06:54									*/
/*													*/
/* EQUINOX-3D(TM), 3DPanel(TM) and 3DLib(TM) Copyright (C) 1995 By Gabor Nagy. All rights reserved.	*/
/*======================================================================================================*/
#include <stdio.h>

#include <EMalloc.h>
#include <EPlugins.h>

#include <EGUI/PushButton.h>


#include <E3D/Matrix.h>

#include <E3D/Scene.h>

#include <E3D/3DWindow.h>

#include <E3D/StatusPanel.h>


static EguiItem		_MenuButtons[16];
static unsigned int	_NumOfMenuButtons=0;

static EBool		_E3dp_ShowMaterials=TRUE;

enum
{
 E3dCR_INFO_ON_SELECTION,
 E3dCR_REMOVE_ATTRIBUTES,
 E3dCR_INFO_LIST_ROOTS,
 E3dCR_INFO_LIST_MATERIALS
};





static void _PrintJointInfo(E3dModel* LModel)
{
 E3dJointModel*	LJointModel=(E3dJointModel*)LModel;


 printf("JOINT\n");

 if(LJointModel->Skin)
 {
  printf("Skin: [%s]\n", LJointModel->Skin->Name);
 }
 else printf("Skin: -\n");
 fflush(stdout);
}


static void E3d_PrintMeshInfo(E3dModel* LModel, E3dMesh* LMesh, unsigned int* LTotalPolyNumP, unsigned int* LSelectedPolyNumP)
{
 E3dPolyGroup*	LPolyGroup;
 E3dPolyGroup**	LPolyGroups;
 E3dPolygon*	LPolygon;
 E3dMaterial*	LMaterial;
 unsigned int	LGCnt, LNumOfTris, LNonTris, LPolyCnt;


 LPolyGroups=LMesh->PolyGroups;
 for(LGCnt=0;LGCnt<LMesh->NumOfPolyGroups;LGCnt++)
 {
  LPolyGroup=LPolyGroups[LGCnt];

  if((LPolyGroup->Selected)||(LMesh->Selection==E3dGSEL_GEOMETRY))
  {
   (*LTotalPolyNumP)+=LPolyGroup->NumOfPolygons;

   printf("  PolyGroup-%d [%s]:  polygons: %d TriangleStrips: %d\n  {\n", LGCnt, LPolyGroup->Name, LPolyGroup->NumOfPolygons, LPolyGroup->NumOfTriangleStrips);

   printf("   Use vertex-normals: ");
   if(LPolyGroup->Flags&E3dUSE_VERTEX_NORMALS) printf("YES\n");
   else printf("NO\n");
   fflush(stdout);

   printf("   Vertex-normal type: ");
   switch(LPolyGroup->VertexNormalType)
   {
    case E3dNormalNONE:
     printf("NONE");
    break;

    case E3dNormalPROCESS:
     printf("FROM PROCESS");
    break;

    case E3dNormalAVERAGED:
     printf("AVERAGED");
    break;

    case E3dNormalFROM_DISCONTINUITY_ANGLE:
     printf("FROM DISCONTINUITY ANGLE: %f degrees\n", LPolyGroup->DiscontinuityAngle);
    break;
   }
   printf("\n");

   if(_E3dp_ShowMaterials)
   {
    if((LMaterial=LPolyGroup->Material)==NULL)
    {
     LMaterial=LPolyGroup->DrawingMaterial;
     if(LMaterial==(&E3d_DefaultMaterial)) printf("   No Material (using default)\n");
     else
     {
      printf("   Inherited Material\n");fflush(stdout);
      E3d_PrintMaterial(LMaterial);
     }
    }
    else
    {
     printf("   PolyGroupMaterial:\n");E3d_PrintMaterial(LMaterial);
    }
   }
   fflush(stdout);
  }


   LNumOfTris=0;

   if((LPolyCnt=LPolyGroup->NumOfPolygons)>0)
   {
    E3dVertex*		LVertices=LMesh->Vertices;
    E3dVertex*		LVertex;
    E3dVertexNode*	LVertexNode;
    unsigned int	LVC;

    LPolygon=LPolyGroup->Polygons;
    do
    {
     if(LPolygon->VertexNodes!=NULL)
     {
      if(LPolygon->Flags&E3dPolyFlagSELECTED)
      {
       LVertexNode=LPolygon->VertexNodes;
       for(LVC=0;LVC<LPolygon->NumOfVertexNodes;LVC++, LVertexNode++)
       {
	LVertex=LVertices+LVertexNode->VertexID;
	printf("%d %f, %f, %f\n", LVertexNode->VertexID, LVertex->X, LVertex->Y, LVertex->Z);
       }
       printf("\n");

       (*LSelectedPolyNumP)++;
      }

      if(LPolygon->NumOfVertices==3)
      {
      }
      else LNonTris++;
     }
     LPolygon++;
    } while(--LPolyCnt);
   }
  printf("  }\n");	// Close PolyGroup

 }



 if(LMesh->GeoType==E3dGEO_SKINMESH)
 {
  E3dSkinMesh*	LSkinMesh=(E3dSkinMesh*)LMesh;

  printf("Number of bones: %d\n", LSkinMesh->NumBones);fflush(stdout);
  printf("SkinVertices %p\n", LSkinMesh->SkinVertices);fflush(stdout);

  if(LSkinMesh->Skeleton)
  {
   printf("Skeleton: [%s]\n", LSkinMesh->Skeleton->Name);fflush(stdout);
  }
 }



 printf(" }\n");	// Close Mesh
}


static void E3d_PrintSplineInfo(E3dModel* LModel, E3dSpline* LSpline)
{
 unsigned int	LC, LN;


 LN=LSpline->NumOfCVs;

 printf(" # of keys: %d  Type:", LN);

 switch(LSpline->SplineType)
 {
  case E3dSPL_BEZIER:
   printf("BEZIER\n");fflush(stdout);
  break;

  case E3dSPL_BSPLINE:
   printf("B-SPLINE\n");fflush(stdout);
  break;

  case E3dSPL_CARDINAL:
   printf("CARDINAL\n");fflush(stdout);
  break;

  case E3dSPL_LINEAR:
   printf("LINEAR\n");fflush(stdout);
  break;
 }

 switch(LSpline->SplineType)
 {
  case E3dSPL_LINEAR:
   {
    E3dSplineCV*	LSplineCV=(E3dSplineCV*)(LSpline->CVs);

    for(LC=0;LC<LN;LC++, LSplineCV++)
    {
     printf(" Position: %f,%f,%f\n", LSplineCV->Position.X, LSplineCV->Position.Y, LSplineCV->Position.Z);
    }
   }
  break;
 }
 fflush(stdout);
}


/*======================================*/
/* Info on selection			*/
/*======================================*/
void E3dp_SelInfo()
{
 E3dModel**	LRootModels;
 E3dModel*	LModel;
 unsigned int	LC, LN, LTotalPolyNum, LSelectedPolyNum;

 LTotalPolyNum=LSelectedPolyNum=0;
 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModels[LC];

  {
   unsigned int		LGmCnt, LGmNum;
   E3dGeometry**	LGeometries;
   E3dGeometry*		LGeometry;
   E3dMesh*		LMesh;

   LTotalPolyNum=0;
   for(;LModel!=NULL;LModel=LModel->Next)
   {
    if(LModel->Selection != E3dSEL_NONE)
    {
printf("Model: %s [%08x]\n", LModel->Name, (unsigned int)LModel);

     switch(LModel->Type)
     {
      case E3dMDL_NORMAL:
       printf("Type: Normal model\n");


/*
       if(_E3dp_ShowMaterials)
       {
	LMaterial=E3d_ModelInheritMaterial(LModel);

	if(LModel->Material!=NULL) { printf("   ModelMaterial:\n");E3d_PrintMaterial(LMaterial); }
	else
	{
	 if(LMaterial==(&E3d_DefaultMaterial)) printf("   No Material (using default)\n");
	 else { printf("   Inherited ModelMaterial:\n");E3d_PrintMaterial(LMaterial); }
	}
       }
*/

       printf("Geometries: %d\n{\n", LModel->NumOfGeometries);

       LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
       for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
       {
	LGeometry=LGeometries[LGmCnt];

Printf("Geo %p\n", LGeometry);fflush(stdout);
	if(LGeometry)
	{
//	 if(LGeometry->Selection!=E3dGSEL_NONE)
	 {
printf(" NumOfModels: %d\n", LGeometry->NumOfModels);fflush(stdout);

	  switch(LGeometry->GeoType)
	  {
	   case E3dGEO_MESH:
	    LMesh=(E3dMesh*)LGeometry;

	    printf(" Geometry #%d MESH: [%s] vertices: %d, polygroup(s): %d\n {\n", LGmCnt, LMesh->Name, LMesh->NumOfVertices, LMesh->NumOfPolyGroups);

	    E3d_PrintMeshInfo(LModel, (E3dMesh*)LGeometry, &LTotalPolyNum, &LSelectedPolyNum);
	   break;

	   case E3dGEO_SKINMESH:
	    LMesh=(E3dMesh*)LGeometry;

	    printf(" Geometry #%d SKINMESH: [%s] vertices: %d, polygroup(s): %d\n {\n", LGmCnt, LMesh->Name, LMesh->NumOfVertices, LMesh->NumOfPolyGroups);

	    E3d_PrintMeshInfo(LModel, LMesh, &LTotalPolyNum, &LSelectedPolyNum);
	   break;

	   case E3dGEO_SPLINE:
	    printf(" Geometry #%d Spline [%s]\n {\n", LGmCnt, LGeometry->Name);

	    E3d_PrintSplineInfo(LModel, (E3dSpline*)LGeometry);
	    printf(" }\n");
	   break;
	  }
         }
	}
        else printf(" Geometry #%d is NULL!!!\n", LGmCnt);
       }
      break;

      case E3dMDL_INSTANCE:
       printf("INSTANCE\n");
      break;

      case E3dMDL_LIGHT:
       printf("LIGHT\n");
      break;

      case E3dMDL_LIGHT_INTEREST:
       printf("LIGHT_INTEREST\n");
      break;

      case E3dMDL_CAMERA:
       printf("CAMERA\n");
      break;

      case E3dMDL_CAMERA_INTEREST:
       printf("CAMERA_INTEREST\n");
      break;

      case E3dMDL_JOINT:
       _PrintJointInfo(LModel);
      break;

      default:
printf("??? %d\n", LModel->Type);
      break;
     }

     printf("}\n");	// Close Model
     if(LModel->Next!=NULL) printf("\n");
    }
   }
  }
 }
 printf("Total # of polygons: %d  selected: %d\n", LTotalPolyNum, LSelectedPolyNum);fflush(stdout);
}


/*======================================*/
/* List RootModels			*/
/*======================================*/
void E3dp_RootsInfo()
{
 E3dModel**	LRootModels;
 E3dModel*	LModel;
 unsigned int	LC, LN;

printf("RootModels:\n");fflush(stdout);

 LRootModels=E3d_Scene->RootModels;
 for(LC=0, LN=E3d_Scene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModels[LC];
printf("[%s] %08x\n", LModel->Name, (unsigned int)LModel);fflush(stdout);
 }

printf("E3d_Scene->NumOfMaterials: %d\n", E3d_Scene->NumOfMaterials);fflush(stdout);

}


/*======================================*/
/* List Materials			*/
/*======================================*/
void E3dp_MaterialsInfo()
{
 E3dMaterial**	LMaterials;
 E3dMaterial*	LMaterial;
 unsigned int	LC, LN;

printf("Materials:\n");fflush(stdout);

 LMaterials=E3d_Scene->Materials;
 for(LC=0, LN=E3d_Scene->NumOfMaterials;LC<LN;LC++)
 {
  LMaterial=LMaterials[LC];
  printf(" %p RefCnt=%d  [%s]\n", LMaterial, LMaterial->RefCnt, LMaterial->Name);fflush(stdout);
 }

printf("E3d_Scene->NumOfMaterials: %d\n", E3d_Scene->NumOfMaterials);fflush(stdout);

}


/*======================================================================================*/
/* Remove ModelInfo from selected Models and GeoInfo from selected Geometries		*/
/*======================================================================================*/
void E3dp_RemoveModelAndGeometryInfo(E3dScene* LScene)
{
 E3dModel**	LRootModels;
 E3dModel*	LModel;
 unsigned int	LC, LN, LAttDelModelN=0, LAttDelGeoN=0;


 LRootModels=LScene->RootModels;
 for(LC=0, LN=LScene->NumOfRootModels;LC<LN;LC++)
 {
  LModel=LRootModels[LC];

  {
   E3dGeometry**	LGeometries;
   E3dGeometry*		LGeometry;
   unsigned int		LGmCnt, LGmNum;
   EBool		LModelSelected;

   for(;LModel!=NULL;LModel=LModel->Next)
   {
    if(LModel->Selection != E3dSEL_NONE)
    {
     E3dM_IsModelSelected(LModel, LModelSelected);

     if(LModel->Info)
     {
      E3dModelClass*	LClass;
      unsigned int	LIC, LIN=LModel->NumOfInfoRecords;

      for(LIC=0;LIC<LIN;LIC++)
      {
       LClass=LModel->Info[LIC]->Class;
       if(LClass->DestroyProc) LClass->DestroyProc(LModel, LModel->Info[LIC]);
       EFree(LModel->Info[LIC]);
      }

      EFree(LModel->Info);LModel->Info=NULL;LModel->NumOfInfoRecords=0;

      LAttDelModelN++;
     }

     switch(LModel->Type)
     {
      case E3dMDL_NORMAL:
       LGmNum=LModel->NumOfGeometries;LGeometries=LModel->Geometries;
       for(LGmCnt=0;LGmCnt<LGmNum;LGmCnt++)
       {
	LGeometry=LGeometries[LGmCnt];

	if((LModelSelected||(LGeometry->Selection!=E3dGSEL_NONE)))
	{
	 if(LGeometry->Info)
	 {
	  E3dGeometryClass*	LClass;
	  unsigned int		LIC, LIN=LGeometry->NumOfInfoRecords;

	  for(LIC=0;LIC<LIN;LIC++)
	  {
	   LClass=LGeometry->Info[LIC]->Class;
	   if(LClass->DestroyProc) LClass->DestroyProc(LModel, LGeometry, LGeometry->Info[LIC]);
	   EFree(LGeometry->Info[LIC]);
	  }

	  EFree(LGeometry->Info);LGeometry->Info=NULL;LGeometry->NumOfInfoRecords=0;

	  LAttDelGeoN++;
	 }

	}
       }
      break;
     }
    }
   }
  }
 }
 if((LAttDelGeoN>0)||(LAttDelModelN>0))
 {
  E3dp_PrintMessage(0, 5000, "Removed attributesfrom %d Model(s) and Geometry(ies)", LAttDelModelN, LAttDelGeoN);
  E3dp_Refresh3DWindows(E3dDF_ALL, E3dVM_ALL);
 }
 else E3dp_PrintMessage(0, 5000, "No Model or Geometry with attributes was selected");
}


/*======================================*/
/* Menu callback			*/
/*======================================*/
static void E3dMCB_Info(EguiItem LGUIItem, EPointer LClientData, EPointer LCallData)
{
 switch((int)LClientData)
 {
  case E3dCR_INFO_ON_SELECTION:
   E3dp_SelInfo();
  break;

  case E3dCR_REMOVE_ATTRIBUTES:
   E3dp_RemoveModelAndGeometryInfo(E3d_Scene);
  break;

  case E3dCR_INFO_LIST_ROOTS:
   E3dp_RootsInfo();
  break;

  case E3dCR_INFO_LIST_MATERIALS:
   E3dp_MaterialsInfo();
  break;
 }
}


/*======================================*/
/* Key callback				*/
/*======================================*/
static void E3dKCB_Info(unsigned short LKey, unsigned int LModifiers, int LKeyEventType, EPointer LClientData)
{
 E3dMCB_Info(NULL, LClientData, NULL);
}



/*======================================*/
/* Entry point of the plugin		*/
/*======================================*/
int Plugin_Init(EPlugin* LPlugin)
{
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Info", "On selection", '\0', "~Shift ~Ctrl <Key>I", "I", FALSE, NULL, E3dMCB_Info, (EPointer)E3dCR_INFO_ON_SELECTION);
 E_KeySetCallback("Info on selection", (unsigned short)'I', 0, EKeyPRESS, E3dKCB_Info, (EPointer)E3dCR_INFO_ON_SELECTION);

 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Info", "Remove attributes", '\0', "Alt <Key>Delete", "Alt+Del", FALSE, "Remove special attributes such as construction history,\nfrom selected Models and Geometries", E3dMCB_Info, (EPointer)E3dCR_REMOVE_ATTRIBUTES);
 E_KeySetCallback("Delete attributes", (unsigned short)EKeyDELETE, EAltMask, EKeyPRESS, E3dKCB_Info, (EPointer)E3dCR_REMOVE_ATTRIBUTES);

 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Info", "List roots", '\0', "~Shift ~Ctrl <Key>R", NULL, FALSE, NULL, E3dMCB_Info, (EPointer)E3dCR_INFO_LIST_ROOTS);
 _MenuButtons[_NumOfMenuButtons++]=EGUI_AddPushButton("Menu->Info", "List Scene Materials", '\0', "~Shift ~Ctrl <Key>R", NULL, FALSE, NULL, E3dMCB_Info, (EPointer)E3dCR_INFO_LIST_MATERIALS);
 return(0);
}


/*======================================*/
/* Exit method of the plugin		*/
/*======================================*/
int Plugin_Exit()
{
 unsigned int	LC;

 for(LC=0;LC<_NumOfMenuButtons;LC++) if(_MenuButtons[LC]) EGUI_DestroyItem(_MenuButtons[LC]);

 E_KeyRemoveCallback((unsigned short)'I', 0, EKeyPRESS, E3dKCB_Info, (EPointer)E3dCR_INFO_ON_SELECTION);
 E_KeyRemoveCallback((unsigned short)EKeyDELETE, EAltMask, EKeyPRESS, E3dKCB_Info, (EPointer)E3dCR_REMOVE_ATTRIBUTES);
 return(0);
}
