/*=========================================================================
*
* A3dSave.c	- save A3D file
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include "A3dSave.h"

#include "conventi.h"
#include "print.h"
#include "system.h"

#include "Banks.h"
#include "Borders.h"
#include "ModLib.h"


//--------------------------------------------------------------------


/****************************************************************************
*		Description:	save A3d file header
*
*		Parameters:		p_stFile	: script file pointer
*						sFileName	: file name
*						p_vPtr		: data pointer
*						xAction		: script action
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveA3dHeader (SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
  xString mes;

  SCR_fn_v_SvL1_DeleteSection(p_stFile);
  SCR_M_SvL0_SaveScriptFileHeader(p_stFile);

  //save the header section of a3d file
  sprintf(mes, "%s%s", M_A3D_HEADER, SCR_CC_sz_Cfg_SectionIdMark);
  SCR_M_SvL0_SaveBeginSection(p_stFile, mes, SCR_CC_C_Cfg_EOL);

  SCR_M_SvL0_SaveEntry(p_stFile, M_OBJActionFileType, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%s", "Animations");

  SCR_M_SvL0_SaveEntry(p_stFile, M_OBJActionVersionNumber, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 6);

  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
}



/****************************************************************************
*		Description:	Save A3D file 
*
*		Parameters:		p_stFile	: script file pointer
*						sFileName	: file name
*						p_vPtr		: data pointer
*						xAction		: script action
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSaveA3dFile (SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
  xString	sFile, sAction, sIdent, mes, sSection;
  float		stQ[4];
  int		i;

  SCR_fn_v_SvL1_ToEndSection(p_stFile);

  // string table
  sprintf(mes, "%d()", 2*g_lGeometricIndex+1);
  sprintf(sFile, "%s.a3d", g_sFileIn);

  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_A3dStringsTable, mes);
  SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(sSection), SCR_CC_C_Cfg_EOL);

  for (i = 0; i < g_lGeometricIndex; i++)
  {
	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
    if (i == 0)
	{   
		sprintf(mes, "%s%d", "Channel", i+1);
		SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%s", 0, mes);
	}
	else
	{	
		if (i == 1)
		{   
			SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
			SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%s", 1, sFile);
			SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
		}
		sprintf(mes, "%s%d", "Channel", i+1);
		SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%s", i+1, mes);
	}
  }
  for (i = g_lGeometricIndex; i < 2*g_lGeometricIndex; i++)
  {
	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i-g_lGeometricIndex]->sName, sFile, sAction, sIdent);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%s", 1+i, sIdent);
  }

  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);

  // vertex table
  sprintf(mes, "%d()", g_lGeometricIndex+2);
  sprintf(sFile, "%s.a3d", g_sFileIn);

  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_A3dVertexesTable, mes);
  SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(sSection), SCR_CC_C_Cfg_EOL);

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 5, "%d,%.5f,%.5f,%.5f", 0, 0.0, 0.0, 0.0); 

  //position matrix!!!!!
  MLT_vGetPositions (&g_hBankRoot);

  for (i = 0; i < g_lGeometricIndex; i++)
  {
	  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 5, "%d,%.5f,%.5f,%.5f", i+1, 
													g_hGeometricInFile[i]->p_stMatrix->stTranslation.xX, 
													g_hGeometricInFile[i]->p_stMatrix->stTranslation.xY, 
													g_hGeometricInFile[i]->p_stMatrix->stTranslation.xZ);
  }

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 5, "%d,%.5f,%.5f,%.5f", g_lGeometricIndex+1, 1.0, 1.0, 1.0);

  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);


  // quaternion table
  sprintf(mes, "%d()", 2*g_lGeometricIndex + 1 );
  sprintf(sFile, "%s.a3d", g_sFileIn);

  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_A3dQuaternionsTable, mes);
  SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(sSection), SCR_CC_C_Cfg_EOL);

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 6, "%d,%d,%d,%d,%d", 0, 0, 0, 0, 1);

  for (i = 0; i < g_lGeometricIndex; i++)
  {
	//compute the quaternion for the rotation matrix
	MLT_vSetQuaternionFromMatrix( g_hGeometricInFile[i]->p_stMatrix->a9_xRotMatrix, stQ);
	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 6, "%d,%e,%e,%e,%f", i+1, stQ[0], stQ[1], stQ[2], stQ[3]);
  }
  for (i = g_lGeometricIndex; i < 2*g_lGeometricIndex; i++)
  {
	//compute the quaternion for the scale matrix
	MLT_vSetQuaternionFromMatrix( g_hGeometricInFile[i-g_lGeometricIndex]->p_stMatrix->a9_xScaleMatrix, stQ);

	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionAdd, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 6, "%d,%e,%e,%e,%f", i+1, stQ[0], stQ[1], stQ[2], stQ[3]);
  }
  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);


  // general section
  sprintf(mes, "%s%s", M_A3dAnimationGENERAL, SCR_CC_sz_Cfg_SectionIdMark);
  SCR_M_SvL0_SaveBeginSection(p_stFile, mes, SCR_CC_C_Cfg_EOL);

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionActor, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%s", g_sFileIn ); 

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionNumberOfChannels, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", g_lGeometricIndex); 
  
  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionNumberOfFrames, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 1); 
  
  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionCurrentFrame, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 1); 

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionTransOffset, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 0); 

  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionRotationOffset, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 0); 
  
  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionReferenceChannel, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 0); 
  
  SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionSpeed, SCR_CC_C_Cfg_NoChar);
  SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 15); 
  

  SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);


  // channel sections
  for (i = 0; i < g_lGeometricIndex; i++)
  {	
	if (i == 0)
		sprintf(mes, "%d(%d)", i+1, i);
	else
		sprintf(mes, "%d(%d)", i+1, i+1);

	sprintf(sFile, "%s.a3d", g_sFileIn);
	SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_A3dChannel, mes);
	SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(sSection), SCR_CC_C_Cfg_EOL);

	SCR_g_ui_SvL0_IndentationLevel = 1;
	
	//first frame
	sprintf(mes, "1()");  
	sprintf(sFile, "%s.a3d", g_sFileIn);
	SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_A3dFrame, mes);
	SCR_M_SvL0_SaveBeginSection(p_stFile, MLT_p_cGetSectionName(sSection), SCR_CC_C_Cfg_EOL);

	SCR_M_SvL0_SaveEntry(p_stFile, M_OBJActionObjectType, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%s", "3dObject" ); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_OBJActionBank, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", 1 ); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_OBJActionObject, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", i+ g_lGeometricIndex+1); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionNumberInTable, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", i+1); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionPosition, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", i+1); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionOrientation, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d", i+1); 

	SCR_M_SvL0_SaveEntry(p_stFile, M_A3DActionScale, SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 3, "%d,%d", i+g_lGeometricIndex+1, g_lGeometricIndex+1); 

	SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
	SCR_g_ui_SvL0_IndentationLevel = 0;

	SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
  }

}


/****************************************************************************
*		Description:	Compute the global positions  
*
*		Parameters:		p_hRoot	: root of the bank
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vGetPositions (MLT_tdxHandleToSuperObject *p_hRoot)
{
	int						i;

	if (!(*p_hRoot)) 
		return;

	for (i=0; i<(*p_hRoot)->lNbChild; i++)
	{  
		(*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xX = (*p_hRoot)->p_stMatrix->stTranslation.xX + (*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xX;
		(*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xY = (*p_hRoot)->p_stMatrix->stTranslation.xY + (*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xY;
		(*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xZ = (*p_hRoot)->p_stMatrix->stTranslation.xZ + (*p_hRoot)->d_hChild[i]->p_stMatrix->stTranslation.xZ;
	}

	// iteration on next level
	for (i=0; i<(*p_hRoot)->lNbChild; i++)
	{
		MLT_vGetPositions(&(*p_hRoot)->d_hChild[i]);
	}
}

/****************************************************************************
*		Description:	Compute the quaternion 
*
*		Parameters:		stMatrix	: a matrix for computing the quaternion
*						stQ			: the computed quaternion
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSetQuaternionFromMatrix( MTH_tdxReal stMatrix[3][3], float stQ[4])
{
  int X=0, Y=1, Z=2, W=3;
  
  // compute quaternion from matrix
  double trace, s;
  
  trace = (double)MTH_M_xRealToFloat( stMatrix[0][0] + stMatrix[1][1] + stMatrix[2][2] );
  if ( trace > 0.0 )
  {
    s = sqrt( trace + 1.0 );
    stQ[W] = (float)(0.5 * s);
    s = 0.5 / s;
    stQ[X] = (float)(( stMatrix[2][1] - stMatrix[1][2] ) * s);
    stQ[Y] = (float)(( stMatrix[0][2] - stMatrix[2][0] ) * s);
    stQ[Z] = (float)(( stMatrix[1][0] - stMatrix[0][1] ) * s);
  }
  else
  {
    int iNext[3] = { Y, Z, X };
    int i, j, k;
    i = X;
    if ( stMatrix[1][1] > stMatrix[0][0] ) i = Y;
    if ( stMatrix[2][2] > stMatrix[i][i] ) i = Z;
    j = iNext[i];
    k = iNext[j];
    s = sqrt( ( stMatrix[i][i] - ( stMatrix[j][j] + stMatrix[k][k] ) ) + 1.0 );
    stQ[i] = (float)(s * 0.5);
    s = 0.5 / s;
    stQ[W] = (float)(( stMatrix[k][j] - stMatrix[j][k] ) * s);
    stQ[j] = (float)(( stMatrix[i][j] + stMatrix[j][i] ) * s);
    stQ[k] = (float)(( stMatrix[i][k] + stMatrix[k][i] ) * s);
  }
}




