#include "SM_Engine3DPCH.h"
#include "SM_FFTBall.h"
#include "SM_KeyFrameSequence.h"
#include "SM_MathPch.h"
#include "SM_Sound.h"
#include "MFastFPU.h"




bool SM_FFTBall::m_bIndices = false;
bool SM_FFTBall::m_bGeometries = false;
Vector3D SM_FFTBall::m_v3dSource[NVERTICESFFT];
Vector3D SM_FFTBall::m_v3dPositions[NVERTICESFFT];
Vector3D SM_FFTBall::m_v3dNormals[NVERTICESFFT];

int guard1=0xFFFFFFFF;
float m_fHeights[ROWSFFT+1][COLUMNSFFT+1];
int guard2=0xFFFFFFFF;
 
void GenerateData(Vector3D* pv3d)
{
  unsigned i,j;

  float v  = 0;
  float du = (1.0f)/(COLUMNSFFT);
  float dv = (1.0f)/(ROWSFFT);

  Vector3D* pOut = pv3d;
  
  float fMax = 0.0f;
  for (j = 0 ; j <= ROWSFFT ; j++)
  {
    float u  = 0;
      for (i = 0 ; i <= COLUMNSFFT ; i++)
    {        
      *pOut = Vector3D(cosf(v*PI), cosf(u*2*PI)*sinf(v*PI), sinf(u*2*PI)*sinf(v*PI))*20.0f;
      //*pOut = Vector3D(v, u, 0.0f)*20.0f;
      pOut++;

      u += du;
    }

    v += dv;
  }  

  for (i = 0 ; i < ROWSFFT ; i++)
  {
    memset(m_fHeights, 0 ,sizeof(float)*COLUMNSFFT);
  }
}



SM_FFTBall::SM_FFTBall      ()
{
}

SM_FFTBall::~SM_FFTBall     ()
{
  Shutdown();
}


int  SM_FFTBall::Init(int iShader, IKFAnimable* pAnimable)    
{
  m_iShader = iShader;
  m_pAnimable = pAnimable;

  return 0;
}

int  SM_FFTBall::Shutdown           ()
{
  return 0;
}

int  SM_FFTBall::Reset              ()
{
  return 0;
}

void SM_FFTBall::Render             (RenderContext* pRenderContext, int iOutcode, float fTime)
{
  static FVF_PosNormalDiffuseTex1 pVertices[(ROWSFFTPERDP+1)*(COLUMNSFFT+1)];    
  static unsigned short pusIndices[ROWSFFTPERDP*COLUMNSFFT*6];
  static bool bIndices = false;
  static bool bGeometries = false;

  // Fill out index list
  if (!bIndices)
  {
    unsigned i,j;
    unsigned short* pI = pusIndices;
    unsigned uCurrent = 0;
    for (j = 0 ; j<ROWSFFT ; j++, uCurrent+=COLUMNSFFT+1)
    {
      for (i = 0 ; i < COLUMNSFFT ; i++)
      {
        /*
        unsigned uV = uCurrent+i;
        pI[0] = uV;
        pI[1] = uV+1;
        pI[2] = uV+COLUMNSFFT+1;
        pI[3] = uV+COLUMNSFFT+1;
        pI[4] = uV+1;
        pI[5] = uV+COLUMNSFFT+2;
        pI+=6;
        */
        unsigned uV = uCurrent+i;


        
          pI[0] = uCurrent+i;
          pI[1] = uCurrent+((i+1)%COLUMNSFFT);
          pI[2] = uCurrent+i+COLUMNSFFT+1;
          pI[3] = uCurrent+i+COLUMNSFFT+1;
          pI[4] = uCurrent+((i+1)%COLUMNSFFT);
          pI[5] = uCurrent+((i+1)%COLUMNSFFT)+COLUMNSFFT+1;
          pI+=6;
        
        
      }
    }

    GenerateData(m_v3dSource);

    bIndices = true;
  }

  

  assert(ROWSFFTPERDP == ROWSFFT);

  
  // Fill out positions/normals
  unsigned i;
  unsigned j;


  
  float fOffset = Timer::GetTime()*1.0f;

  float fFigure = fOffset*0.5f;



  float* pfData;
  
  
  if (SM_Sound::GetFFT(fTime, pfData))
  {
    float fAux = fmodf(fTime, 20.0f);
    int iRow = ROWSFFT/2;

    static int iOffset = 0;

    for (i = 0 ; i <= COLUMNSFFT/2 ; i++)
    {
      float fHeight = pfData[i];
      m_fHeights[iOffset][COLUMNSFFT/2-i] = fHeight;
      m_fHeights[iOffset][COLUMNSFFT/2+i] = fHeight;
    }
    

    for (j = 0 ; j <= ROWSFFT ; j++)
    {
      int iDistance = j;

      float* ph = m_fHeights[(iOffset+iDistance)%ROWSFFT];

      int c = (COLUMNSFFT+1)*j;
      for (i = 0 ; i <= COLUMNSFFT ; i++)
      {
        m_v3dPositions[c+i] = m_v3dSource[c+i]*(0.8f+ph[i]*1.5f);
        //m_v3dPositions[c+i] = m_v3dSource[c+i]+(ph[i])*Vector3D(0.0f, 0.0f, -10.0f);
      }
    }

    iOffset = int(iOffset+1)%(ROWSFFT);
  }
  else
  {
    for (i = 0 ; i < NVERTICESFFT ; i++)
    {
      m_v3dPositions[i] = m_v3dSource[i];
    }
  }
  
  
  Vector3D* pvNormal=new Vector3D[NPRIMITIVESFFT*3];
  int iTri;
  for (i=0, iTri=0 ; i<NPRIMITIVESFFT*3 ; i+=3, iTri++)
  {
    pvNormal[iTri]=
      Vector3D::Cross(
        m_v3dPositions[pusIndices[i+1]]-m_v3dPositions[pusIndices[i]],
        m_v3dPositions[pusIndices[i+2]]-m_v3dPositions[pusIndices[i]]
        );
  }

  Vector3D* pvVertexNormal=new Vector3D[NVERTICESFFT];
  memset(pvVertexNormal, 0, sizeof(Vector3D)*NVERTICESFFT);
  for (i=0, iTri=0 ; i<NPRIMITIVESFFT*3 ; i+=3, iTri++)
  {
    pvVertexNormal[pusIndices[i]]  +=pvNormal[iTri];
    pvVertexNormal[pusIndices[i+1]]+=pvNormal[iTri];
    pvVertexNormal[pusIndices[i+2]]+=pvNormal[iTri];
  }

  for (i=0 ; i<NVERTICESFFT ; i++)
  {
    m_v3dNormals[i] = pvVertexNormal[i].Normalize();
  }

  delete[] pvNormal;
  delete[] pvVertexNormal;

  MeshElement me;
      
  me.m_iShader            =m_iShader;
  me.m_iVB                =-1;
  me.m_iIB                =-1;
  me.m_pIndices           =pusIndices;
  me.m_pVertices          =pVertices;
  me.m_uStartVertex       =0;
  me.m_uVertices          =NVERTICESFFT;
  me.m_uStartIndex        =0;
  me.m_uPrimitives        =NPRIMITIVESFFT;
  me.m_iActiveLightMask   =-1;  
  me.m_fDepth             =0.0f;


  Vector3D Pos;
  Quaternion q;


  if (m_pAnimable->m_pKeyFrameSequence)
  {
    m_pAnimable->m_pKeyFrameSequence->GetKeyFrame(fTime, 
                                                  m_pAnimable->m_fKeyFrameSequenceStartTime,
                                                  &Pos,
                                                  &q);
  }
  else
  {
    Pos = m_v3dPosition;
    q = m_qRotation;
  }


  
  ToTransform(&me.m_WorldTransform, &Pos, &q);
  
  Vector3D* pV = m_v3dPositions;
  Vector3D* pN = m_v3dNormals;

  FVF_PosNormalDiffuseTex1* pDVBVertices;
  unsigned short*           pDIBIndices;
  int                       iVertexOffset, iIndexOffset;        
  
  // Allocate VB and IB
  if ((iVertexOffset=ResourceManager::GiveVBChunk(ResourceManager::m_iPosNormalDiffuseTex1Stream, NVERTICESFFT*sizeof(FVF_PosNormalDiffuseTex1), (void**)&pDVBVertices))==-1)
  {
    assert(0);
  }

  if ((iIndexOffset=ResourceManager::GiveIBChunk(ResourceManager::m_iIndexStream, NPRIMITIVESFFT*3*sizeof(unsigned short), (void**)&pDIBIndices))==-1)
  {
    assert(0);
  }

  FVF_PosNormalDiffuseTex1* pG = pDVBVertices;
  for (i=0 ; i<NVERTICESFFT ; i++)
  {      
    pG ->x=pV->x; pG ->y=pV->y; pG ->z=pV->z; 
    pV++;
    pG ->nx=pN->x; pG ->ny=pN->y; pG ->nz=pN->z;
    pN++;
    pG ->diffuse=0xFFFFFFFF;
    pG++;                     
  }    

  memcpy(pDIBIndices, pusIndices, sizeof(unsigned short)*NPRIMITIVESFFT*3);

  ResourceManager::DoneVBChunk(ResourceManager::m_iPosNormalDiffuseTex1Stream);
  ResourceManager::DoneIBChunk(ResourceManager::m_iIndexStream);

  unsigned uStartIndex =iIndexOffset/sizeof(unsigned short);
  unsigned uStartVertex=iVertexOffset/sizeof(FVF_PosNormalDiffuseTex1);

  me.m_iVB          =ResourceManager::m_iPosNormalDiffuseTex1Stream;
  me.m_iIB          =ResourceManager::m_iIndexStream;
  me.m_pIndices     =0;
  me.m_pVertices    =0;    
  me.m_uStartVertex = uStartVertex;
  me.m_uStartIndex  = uStartIndex;

  RenderPipeline::Render(&me);
  RenderPipeline::Flush();   

  assert(guard1==0xFFFFFFFF && guard2==0xFFFFFFFF);
}
