#include "SM_Engine3DPCH.h"
#include "SM_Terrain.h"



struct TerrainVertex
{
  float x,y,z;
};

struct TerrainTile
{
    unsigned m_uX;
    unsigned m_uY;
    float    m_fGridResolution;
    int      m_iCachedGeometry;
    int      m_iSons[4];
};

#define FVF_TERRAINVERTEX (D3DFVF_XYZ)
#define TILESIZE          16

int Terrain::Init          ()
{
  unsigned uTileSize=TILESIZE;
  unsigned uWidth   =1024;
  unsigned uHeight  =1024;

  m_pMeshElements=new MeshElement[1];

  MSurface s;
  if (s.Load("data/textures/jardinera.tga")!=0)
  {
    return (-1);
  }

  m_pMeshElements->m_iShader      =ResourceManager::CreateTextureFromSurface(&s, D3DFMT_X8R8G8B8);
  m_pMeshElements->m_uStartVertex =0;
  m_pMeshElements->m_uVertices    =(uTileSize+1)*(uTileSize+1);

  // Vertices
  m_pMeshElements->m_iVB          =ResourceManager::CreateVertexBuffer(
    sizeof(TerrainVertex)*(uTileSize+1)*(uTileSize+1), 
    D3DUSAGE_WRITEONLY, 
    FVF_TERRAINVERTEX, 
    D3DPOOL_MANAGED);

  unsigned i,j;
  IDirect3DVertexBuffer8* pVertexBuffer; 
  TerrainVertex* pVertices;

  pVertexBuffer=ResourceManager::GetVertexBufferFromID(m_pMeshElements->m_iVB);
  pVertexBuffer->Lock(0, sizeof(TerrainVertex)*(uTileSize+1)*(uTileSize+1), (BYTE**) &pVertices, 0);

  for (j=0 ; j<uTileSize+1 ; j++)
  {
    for (i=0 ; i<uTileSize+1 ; i++)
    {
      unsigned uOffset=(uTileSize+1)*j+i;
      unsigned uRead  =(uTileSize+1)*(j+512)+i+512;
      pVertices[uOffset].x=float(i);
      pVertices[uOffset].y=float(j);
      pVertices[uOffset].z=10.0f*sinf(float(i)/10.0f);        
    }
  }
  
  pVertexBuffer->Unlock();
    
  unsigned short* pusIndices         =new unsigned short[uTileSize*uTileSize*6];
  unsigned short* pusOptimizedIndices=new unsigned short[uTileSize*uTileSize*6];
  

  unsigned uOffset=0;
  for (j=0 ; j<uTileSize ; j++)
  {
    for (i=0 ; i<uTileSize ; i++)
    {
      pusIndices[uOffset++]=(uTileSize+1)*(j+0)+(i+0);      
      pusIndices[uOffset++]=(uTileSize+1)*(j+0)+(i+1);      
      pusIndices[uOffset++]=(uTileSize+1)*(j+1)+(i+1);      
      pusIndices[uOffset++]=(uTileSize+1)*(j+0)+(i+0);      
      pusIndices[uOffset++]=(uTileSize+1)*(j+1)+(i+0);      
      pusIndices[uOffset++]=(uTileSize+1)*(j+1)+(i+1);      
    }
  }
  assert(uOffset==uTileSize*uTileSize*6);


  

  //OptimizeIndexList(pusOptimizedIndices, pusIndices, uTileSize*uTileSize*6);  
  
  m_pMeshElements->m_iIB =ResourceManager::CreateIndexBuffer(
      uTileSize*uTileSize*6*sizeof(unsigned short), 
      D3DUSAGE_WRITEONLY , 
      D3DFMT_INDEX16, 
      D3DPOOL_MANAGED);

  IDirect3DIndexBuffer8* pIndexBuffer; 
  pIndexBuffer=ResourceManager::GetIndexBufferFromID(m_pMeshElements->m_iIB);
    

  unsigned short* pusIBIndices;
  pIndexBuffer->Lock(0, uTileSize*uTileSize*6*sizeof(short),(BYTE**) &pusIBIndices, 0);
  memcpy(pusIBIndices, pusIndices, uTileSize*uTileSize*6*sizeof(short));
  pIndexBuffer->Unlock();

  delete[] pusIndices         ; pusIndices  =0;
  delete[] pusOptimizedIndices; pusOptimizedIndices=0;

  


  m_pMeshElements->m_uStartIndex=0;
  m_pMeshElements->m_uPrimitives=uTileSize*uTileSize;
      
  return (0); 
}

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

void Terrain::Render(RenderContext* pRenderContext, int iOutcode)
{
  // World Matrix
  Matrix4X4 m=Matrix4X4::Identity;
  SM_D3d::Device()->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&m);  

  // VB
  IDirect3DVertexBuffer8* pVB;
  IDirect3DIndexBuffer8 * pIB;

  pIB=ResourceManager::GetIndexBufferFromID (m_pMeshElements->m_iIB); assert(pIB);
  pVB=ResourceManager::GetVertexBufferFromID(m_pMeshElements->m_iVB         ); assert(pIB);


  SM_D3d::Device()->SetIndices(pIB, m_pMeshElements->m_uStartIndex);
  SM_D3d::Device()->SetStreamSource(0, pVB, sizeof(TerrainVertex));
  SM_D3d::Device()->SetVertexShader( FVF_TERRAINVERTEX );


  Matrix4X4 mTexCoord;
  Matrix4X4 mInverseView;
  Matrix4X4 mResult;

  pRenderContext->GetViewport()->InverseViewMatrix(mInverseView);
  
  mTexCoord=Matrix4X4::Identity;
  mTexCoord.m_11=1.0f/float(TILESIZE+1);
  mTexCoord.m_22=1.0f/float(TILESIZE+1);

  Matrix4X4::Mult(&mResult, &mInverseView, &mTexCoord);

  SM_D3d::Device()->SetTexture(0, ResourceManager::GetTextureFromID(m_pMeshElements->m_iShader));  
  SM_D3d::Device()->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX*)&mResult);
  SM_D3d::SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
  SM_D3d::SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
  SM_D3d::SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
  SM_D3d::SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);  
  SM_D3d::SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);

  //SM_D3d::SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
  SM_D3d::SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  

  for (int i=0 ; i<1 ; i++)
  {
    SM_D3d::Device()->DrawIndexedPrimitive(
          D3DPT_TRIANGLELIST, 0, (TILESIZE+1)*(TILESIZE+1), 0, TILESIZE*TILESIZE*2);    
  }
}