/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Light related functions						*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Sep-12 23:16:34					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#include <math.h>
#include <float.h>
#include <stdio.h>

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

#include <Color/Color.h>

#include <E3D/E3D.h>

#include <E3D/Light.h>

#include <E3D/Matrix.h>

#include <E3D/Scene.h>


E3dLightInfo	E3d_LightModelInfo;


/*==============================================*/
/* Initialize light				*/
/*==============================================*/
void E3d_LightDefault(E3dLight* LLight)
{
 LLight->RefCnt=0;

 LLight->Name=NULL;
 LLight->Prefix=NULL;
 LLight->FileName=NULL;
 LLight->Type=E3dLIGHT_POINT;
 E3d_3DPositionInit(&(LLight->Position), 0.0, 0.0, 0.0);
 E3d_VectorInit(&(LLight->Direction), 0.0, 1.0, 0.0);
 Ec_SetRGBfColor(&(LLight->Color), 1.0, 1.0, 1.0);
 E3d_3DPositionInit(&(LLight->SchemPosition), 0.0, 0.0, 0.0);
 LLight->ConstAttenuation=1.0;
 LLight->LinAttenuation=0.0;
 LLight->QuadraticAttenuation=0.0;

 LLight->ShadowBrightness=0.5;

 LLight->Model=NULL;
}


/*==============================================================================================*/
/* Allocate a light source									*/
/*												*/
/* Description											*/
/*  This function allocates and initializes an E3dLight structure.				*/
/*												*/
/* Return value											*/
/*  Pointer to the allocated E3dLight structure or NULL in case of an error.			*/
/*												*/
/* See also											*/
/*  E3d_LightFree										*/
/*==============================================================================================*/
E3dLight* E3d_LightAllocate()
{
 E3dLight*	LLight;

 if((LLight=(E3dLight*)EMalloc(sizeof(E3dLight)))!=NULL)
 {
  E3d_LightDefault(LLight);
 }
 return(LLight);
}


/*==============================================================================================*/
/* Free a light source										*/
/*												*/
/* Argument											*/
/*  E3dLight* LLight         Pointer to the Light structure to be freed				*/
/*												*/
/* Description											*/
/*  This function first decrements the reference count (RefCnt) of the given Light		*/
/*  structure (if it's not already zero).							*/
/*  After that, if RefCnt is still greater than zero, it means that this Light is being		*/
/*  being referred to somewhere else, so E3d_LightFree() will simply return.			*/
/*  If RefCnt is zero, E3d_LightFree() will free the memory associated with the light source	*/
/*												*/
/* See also											*/
/*  E3d_LightAllocate										*/
/*==============================================================================================*/
void E3d_LightFree(E3dLight* LLight)
{
 if(LLight)
 {
  if(LLight->RefCnt>0)
  {
   LLight->RefCnt-=1;
   if(LLight->RefCnt>0) return;
  }

  E3d_SceneRemoveLight(E3d_Scene, LLight);

  if(LLight->Model) E3d_ModelFree(LLight->Model);
  EFree(LLight);
 }
}


/*======================================*/
/* Refresh references of a light source	*/
/*======================================*/
void E3d_LightRefresh(E3dLight* LLight, E3dMatrix LCameraTransMatrix)
{
 E3dModel*	LModel=NULL;
 E3dCoordinate	mX, mY, mZ, LF;

// Update camera-transformed position
//
 mX=LLight->Position.X;mY=LLight->Position.Y;mZ=LLight->Position.Z;
 E3dM_MatrixTransform3x4(LCameraTransMatrix, LLight->CamTransPosition.X, LLight->CamTransPosition.Y, LLight->CamTransPosition.Z);

 LF=sqrt(mX*mX+mY*mY+mZ*mZ);
 if(LF!=0.0)
 {
  LF=1.0/LF;
  mX*=LF;mY*=LF;mZ*=LF;
 }

 LLight->Direction.X=mX;
 LLight->Direction.Y=mY;
 LLight->Direction.Z=mZ;
 E3dM_MatrixTransform3x3(LCameraTransMatrix, LLight->CamTransDirection.X, LLight->CamTransDirection.Y, LLight->CamTransDirection.Z);

// Update pseudo-Model of the Light if it has one
//
 if((LModel=LLight->Model)!=NULL)
 {
  E3d_3DPositionCopy(&(LLight->Position), &(LModel->Translation));
  E3d_ModelHrcRefreshMatrices(LModel);

  E3d_ModelUpdateForDisplay(LModel, FALSE);
 }
}


/*======================================================*/
/* Create new LightInfo structure for a Model		*/
/*======================================================*/
E3dModelInfo* E3d_LightCreateModelInfo(E3dLight* LLight)
{
 E3dLightInfo*	LLightInfo;

 LLightInfo=(E3dLightInfo*)EMalloc(sizeof(E3dLightInfo));

 if(LLightInfo) memcpy(LLightInfo, &E3d_LightModelInfo, sizeof(E3dLightInfo));

 return((E3dModelInfo*)LLightInfo);
}
