/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Basic functions							*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Sep-12 21:38:49					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <sys/time.h>

#include <EMalloc.h>
#include <EStrings.h>

#include <E3D/Matrix.h>

#include <E3D/Model.h>


//========================================
// Get UNIX seconds
//========================================
long E3d_GetSeconds()
{
 struct timeval		LTV;
 struct timezone	LTZ;

 if(gettimeofday(&LTV, &LTZ)!=-1)
 {
  return(LTV.tv_sec);
 }
 return(0);
}



//========================================
// Create a KD tree node
//========================================
E3dKDNode* E3d_KDNodeAllocate(unsigned int LStructSize)
{
 E3dKDNode*	LNode=(E3dKDNode*)EMalloc(sizeof(E3dKDNode));

 if(LNode)
 {
  LNode->Child=NULL;
  LNode->Parent=NULL;
  LNode->NextSibling=NULL;
 }
 return(LNode);
}


//========================================
// Free a KD tree
//========================================
void E3d_KDTreeFree(E3dKDNode* LNode)
{
}


//========================================
// Add set to a KD tree
//========================================
void E3d_KDTreeAddSet(E3dKDNode* LTree, int LDepth)
{
}





//========================================
// Set LF to the closest multiple of LS
//========================================
E3dCoordinate E3d_SnapCoordinateTo(E3dCoordinate LF, E3dCoordinate LS)
{
 int	LD;

 if(LF<0.0) LD=(int)((LF-0.5*LS)/LS);
 else LD=(int)((LF+0.5*LS)/LS);
 return(((E3dCoordinate)LD)*LS);
}


//================================================================
// Calculate shade of a color by the luminance of another one
//================================================================
void E3d_ColorShadeByLuma(EcRGBAiColor* LColorLum, EcRGBAiColor* LColor, EcRGBAiColor* LColorRet)
{
 unsigned long	LLuma;

 LLuma=EcM_LumaI((LColorLum->R)>>8, (LColorLum->G)>>8, (LColorLum->B)>>8);
 LColorRet->R=(LColor->R*LLuma)>>8;
 LColorRet->G=(LColor->G*LLuma)>>8;
 LColorRet->B=(LColor->B*LLuma)>>8;
}


//========================================
// Initialize a 3DPosition
//========================================
void E3d_3DPositionInit(E3d3DPosition* LPosition, double LX, double LY, double LZ)
{
 LPosition->X=LX;LPosition->Y=LY;LPosition->Z=LZ;
}


//========================================
// Copy a 3DPosition
//========================================
void E3d_3DPositionCopy(E3d3DPosition* LSrcPosition, E3d3DPosition* LDstPosition)
{
 LDstPosition->X=LSrcPosition->X;
 LDstPosition->Y=LSrcPosition->Y;
 LDstPosition->Z=LSrcPosition->Z;
}


//========================================
// Initialize a Vector
//========================================
void E3d_VectorInit(E3dVector* LVector, double LX, double LY, double LZ)
{
 LVector->X=LX;LVector->Y=LY;LVector->Z=LZ;
 LVector->Length=sqrt(LX*LX+LY*LY+LZ*LZ);
}


//========================================
// Copy a Vector
//========================================
void E3d_VectorCopy(E3dVector* LSrcVector, E3dVector* LDstVector)
{
 LDstVector->X=LSrcVector->X;
 LDstVector->Y=LSrcVector->Y;
 LDstVector->Z=LSrcVector->Z;
 LDstVector->Length=LSrcVector->Length;
}


//========================================
// Cross product of two Vectors
//========================================
void E3d_VectorCrossProduct(E3dVector* LVectorA, E3dVector* LVectorB, E3dVector* LVectorC)
{
 E3dCoordinate	LAX, LAY, LAZ, LBX, LBY, LBZ;

 LAX=LVectorA->X;LAY=LVectorA->Y;LAZ=LVectorA->Z;
 LBX=LVectorB->X;LBY=LVectorB->Y;LBZ=LVectorB->Z;
 LVectorC->X = LAY*LBZ - LAZ*LBY;
 LVectorC->Y = LAZ*LBX - LAX*LBZ;
 LVectorC->Z = LAX*LBY - LAY*LBX;
}


//========================================
// Initialize a rotation
//========================================
void E3d_RotationInit(E3dRotation* LRotation, double LX, double LY, double LZ)
{
 LRotation->X=LX;LRotation->Y=LY;LRotation->Z=LZ;
}


//========================================
// Allocate points array
//========================================
E3dPoint* E3d_PointsAllocate(unsigned int LNumOfPoints)
{ 
 register E3dPoint*	LPoints;
 register unsigned long	LECnt;

 if(LNumOfPoints>0)
 {
  if((LPoints=(E3dPoint*)EMalloc(sizeof(E3dPoint)*LNumOfPoints))!=NULL)
  {
   for(LECnt=0;LECnt<LNumOfPoints;LECnt++)
   {
    LPoints[LECnt].Color=0xFFFFFFFF;
#ifdef USEOpenGL
    LPoints[LECnt].GLColor=0xFFFFFFFF;
#endif // USEOpenGL
   }
  }
  return(LPoints);
 }
 return(NULL);
}


//========================================
// Allocate a Points Geometry
//========================================
E3dPoints* E3d_PointsGeomAllocate()
{
 E3dPoints*	LPoints=(E3dPoints*)EMalloc(sizeof(E3dPoints));

 if(LPoints)
 {
  E3dM_GeometryDefault((E3dGeometry*)LPoints);
  LPoints->GeoType=E3dGEO_POINTS;
  LPoints->NumOfPoints=0;
  LPoints->Points=NULL;
  return(LPoints);
 }
 return(NULL);
}


//========================================
// Free a Points Geometry
//========================================
void E3d_PointsFree(register E3dPoints* LPoints)
{
 if(LPoints->Points) EFree(LPoints->Points);
 EFree(LPoints);
}


//========================================================
// Call callbacks of an Item
//========================================================
void E3d_CallCallbacks(void* LItem, E3dCallbackRec* LCallbacks, unsigned int LNumOfCallbacks, EPointer LCallData)
{
 E3dCallbackProc	LCFunct;
 unsigned int		LC;

 if(LCallbacks)
 {
  for(LC=0;LC<LNumOfCallbacks;LC++)
  {
   LCFunct=LCallbacks[LC].Proc;
   LCFunct(LItem, LCallbacks[LC].ClientData, LCallData);
  }
 }
}


//========================================================
// Call Outputs of an Item
//========================================================
EBool E3d_CallOutputs(void* LItem, E3dInterface** LOutputs, unsigned int LNumOfOutputs, EPointer LCallData)
{
 E3dInterfaceProc	LCFunct;
 E3dInterface*		LOutput;
 unsigned int		LC;
 EBool			LDoRedraw=FALSE;

 if(LOutputs)
 {
  for(LC=0;LC<LNumOfOutputs;LC++)
  {
   LOutput=LOutputs[LC];
   LCFunct=LOutput->Proc;

   if(LCFunct(LItem, LOutput->ClientData, LCallData)) LDoRedraw=TRUE;
  }
 }
 return(LDoRedraw);
}
