#include "SM_CommonFXPCH.h"
#include <math.h>
#include "SM_ResourceManager.h"
#include "SM_CommonVF.h"
#include "SM_RenderContext.h"
#include "SM_D3D.h"
#include "SM_Music.h"
#include "SM_Shader.h"
#include "SM_Sound.h"
#include "Ml.h"
#include "SM_MaxScene.h"
#include "MSystemFunctions.h"
#include "SM_Timer.h"
#include "SM_Slider.h"
#include "FxFilter.h"
#include "FXEscena3D.h"
#include "FXMusic.h"



extern MusicFX MP301;
    
static  SM_DemoEffect::Helper  LoadHelp[] =
{
  {"filename.txt", "loads scene with name filename. It will search for the filename.3px\r\n in data/scenesbin/.\r\nIf it doesnt find it there, it will search\r\nfor filename.txt in data/scenes/"},
};

static SM_DemoEffect::Helper CommandsHelp[] =
{
  {"SHOW","shows the scene. by default the scene is showed"},
  {"HIDE", "hides the scene"},
  {"SETTIME time", "sets an offset in the animation time"},
  {"SETABSOLUTETIME time", "sets the animation time"},  
  {"SETSPEED speed", "sets the animation speed"},  
  {"CAMERA cameraname", "sets cameraname as the current camera"},
  {"FOG ON startfog endfog r g b", "sets linear fog from startfog to endfog (range is 0..1)"},
  {"FOG OFF", "turns fog off"},
  {"VERTEXCOLORS ON", "turns vertex colors on"},
  {"VERTEXCOLORS OFF", "turns vertex colors off"},
  {"VIEWPORT x y w h", "sets viewport, coords are assumed to be from 0 to 640 and 0 to 480"},
  {"VIEWPORT x y w h time", "morphs viewport. coords are assumed to be from 0 to 640 and 0 to 480"},
  {"NOISE x y z time", "camera will have noise and fade out in time"},
  {"FLIPX ON", "mirror x on"},
  {"FLIPX OFF", "mirror x off (default)"},
  {"FLIPY ON", "mirror y on"},
  {"FLIPY OFF", "mirror y off (default)"},
  {"SHADOWS ON", "shadows on"},
  {"SHADOWS OFF", "shadows off"},
  {"PARTICLEPARAMS nombreobjeto parametros", "manda parametros a sistema de particulas"},  
  {"PARTICLEPARAMS nombreobjeto tamanyo tiempodevida particulasporsegundo vx vy vz ax ay az", "manda parametros a sistema de particulas"},    
  {"PARTICLEPARAMS nombreobjeto tamanyo tiempodevida particulasporsegundo vx vy vz ax ay az radiodisco", "manda parametros a sistema de particulas"},    
  {"BEATFORWARD OFF", "desactiva forward con beat"},
  {"BEATFORWARD tiempo", "forwardea la escena con cada beat el tiempo indicado"},
};


int Escena3D::LoadArgumentsHelp     (Helper*& pHelpers)
{
  pHelpers = LoadHelp;
  return (sizeof(LoadHelp)/sizeof(Helper));
}

int Escena3D::CommandArgumentsHelp  (Helper*& pHelpers)
{
  pHelpers = CommandsHelp;
  return (sizeof(CommandsHelp)/sizeof(Helper));
}



Escena3D::Escena3D(char const* pcName) : SM_DemoEffect(pcName)
{
  Reset();
}

Escena3D::~Escena3D()
{
}

int Escena3D::Init(const char* pcCommand)
{
  char  pcPath[256];
  MVFSFILE* pFile=0;
  
  int iReturn = -1;
  
  char* pcCopy=new char[strlen(pcCommand)+1];
  strcpy(pcCopy, pcCommand);
 
  char* pcToken=strtok(pcCopy, " \t");
  if (!pcToken)
  {
    return -1;
  }

  strcpy(pcPath, "data/scenes/");
  strcat(pcPath, pcToken);    

  char pcCompiledName[_MAX_PATH];
  char pcBaseName[_MAX_PATH];
  MExtractBasename(pcBaseName, pcPath);

  strcpy(pcCompiledName,  "data/scenesbin/");
  strcat(pcCompiledName, pcBaseName);
  strcat(pcCompiledName, ".3PX");

  if (m_MaxScene.Init() != 0)
  {
    return -1;
  }
  
  #ifdef MAXSCENE_IMPORTER
  if ( !(pFile=MVFS::fopen(pcCompiledName, "rb")) )
  {
    pFile=MVFS::fopen(pcCompiledName, "wb");

    if (m_MaxScene.CompileML(pcPath, pFile)!=0)
    {
      goto EXIT;
    }        
  }
  MVFS::fclose(pFile);    
  #endif

  pFile=MVFS::fopen(pcCompiledName, "rb");
  if (!pFile || m_MaxScene.LoadBin(pFile)!=0)
  {
    MVFS::unlink(pcCompiledName);
    goto EXIT;
  }
  MVFS::fclose(pFile);            
  pFile=0;

  m_bLoaded= true;

  m_MaxScene.PreCache();

  iReturn = 0;
EXIT:
  if (pFile)  { MVFS::fclose(pFile); pFile=0; }
  if (pcCopy) { delete[] pcCopy; pcCopy=0; }
  return iReturn;  
}

int Escena3D::Shutdown()
{
  m_MaxScene.Shutdown();
  return (0);
}

int Escena3D::Reload(const char* pcCommand)
{
  char  pcPath[256];
  MVFSFILE* pFile=0;
  
  int iReturn = -1;
  
  char* pcCopy=new char[strlen(pcCommand)+1];
  strcpy(pcCopy, pcCommand);
 
  char* pcToken=strtok(pcCopy, " \t");
  if (!pcToken)
  {
    return -1;
  }

  strcpy(pcPath, "data/scenes/");
  strcat(pcPath, pcToken);    

  char pcCompiledName[_MAX_PATH];
  char pcBaseName[_MAX_PATH];
  MExtractBasename(pcBaseName, pcPath);

  strcpy(pcCompiledName,  "data/scenesbin/");
  strcat(pcCompiledName, pcBaseName);
  strcat(pcCompiledName, ".3PX");

  MVFS::unlink(pcCompiledName);
  
  if (pcCopy) { delete[] pcCopy; pcCopy=0; }
  
  return SM_DemoEffect::Reload(pcCommand);  
}

int Escena3D::Start(float fTime)
{
  m_MaxScene.SetStartTime(fTime);
  return (0);
}

int Escena3D::Stop()
{
  //m_MaxScene.ClearCache();
  return (0);
}

int Escena3D::Reset()
{
  m_bVisible      =true;
  m_fForwardLength=0.0f;
  m_fAnimationOffset=0.0;
  m_fStartForward   =0.0f;  

  m_VAx=0.0f; m_VAy=0.0f;  m_VAw=640.0f, m_VAh=480.0f;
  m_VBx=0.0f; m_VBy=0.0f;  m_VBw=640.0f, m_VBh=480.0f;    
  m_bViewportTransition=false;

  m_bBeatForward  = false;
  m_fBeatForward  =0.0f;
  

  m_MaxScene.Reset();
  
  return (0);
}

int Escena3D::Run(float fTime)
{
  if (m_bLoaded && m_bVisible)
  {
    float fOffset=0.0f;
    if (m_fForwardLength)
    {
      fOffset=1.0f/(1.0f+(float)exp(-(75.0f*(-0.05+Timer::GetTime()-m_fStartForward))));

      if (fOffset>0.99f)
      {
        m_fAnimationOffset+=1.0f;
        m_fForwardLength=0.0f;
        fOffset=0.0f;
      }
    }
    
    if (m_bViewportTransition)
    {
      float fInterp;

      m_bViewportTransition=m_ViewportSlider.GetValue(Timer::GetTime(), &fInterp);

      m_MaxScene.m_fX=(m_VAx+(m_VBx-m_VAx)*fInterp);
      m_MaxScene.m_fY=(m_VAy+(m_VBy-m_VAy)*fInterp);
      m_MaxScene.m_fWidth=(m_VAw+(m_VBw-m_VAw)*fInterp);
      m_MaxScene.m_fHeight=(m_VAh+(m_VBh-m_VAh)*fInterp);           
    }
    else
    {
      m_MaxScene.m_fX=m_VBx;
      m_MaxScene.m_fY=m_VBy;
      m_MaxScene.m_fWidth=m_VBw;
      m_MaxScene.m_fHeight=m_VBh;                          
    }

    // Parche      
    //m_MaxScene.SetAnimationOffset(fOffset+m_fAnimationOffset);
    if (m_bBeatForward &&
        SM_Sound::IsBeat(fTime))
    {
      m_MaxScene.SetStartTime(m_MaxScene.m_fStartTime-m_fBeatForward);
    }

    //g_SceneFilter->SetRenderDepthTarget(0);
    m_MaxScene.Render(0, 0xFFFFFFFF, false);
    //g_SceneFilter->RestoreRenderDepthTarget();



    
           
    
/*
    FVF_PosRhwDiffuseTex1 pVertices[4];
    unsigned short        pIndices[6]={0,2,1,0,3,2};
    SM_D3d::Device()->SetTexture(0, ResourceManager::GetTextureFromID(g_SceneFilter->m_iFakeBufferID));    


 
    float fScaleU=1.0f;
    float fScaleV=1.0f;    

    float fxCenter=320.0f;
    float fyCenter=240.0f;

    float fxWidth=320.0f;
    float fyHeight=240.0f;

    float fScale  =1.0f+0.0f*sinf(fTime);

    pVertices[0].x=fxCenter-fxWidth*fScale; pVertices[0].y=fyCenter-fyHeight*fScale ; pVertices[0].z=0.0f; pVertices[0].u=0.0f; pVertices[0].v=0.0f; pVertices[0].oow=1.0f; pVertices[0].diffuse=0xFFFFFFFF;
    pVertices[1].x=fxCenter+fxWidth*fScale; pVertices[1].y=fyCenter-fyHeight*fScale ; pVertices[1].z=0.0f; pVertices[1].u=fScaleU; pVertices[1].v=0.0f; pVertices[1].oow=1.0f; pVertices[1].diffuse=0x00FFFFFF;
    pVertices[2].x=fxCenter+fxWidth*fScale; pVertices[2].y=fyCenter+fyHeight*fScale; pVertices[2].z=0.0f; pVertices[2].u=fScaleU; pVertices[2].v=fScaleV; pVertices[2].oow=1.0f; pVertices[2].diffuse=0xFFFFFFFF;
    pVertices[3].x=fxCenter-fxWidth*fScale; pVertices[3].y=fyCenter+fyHeight*fScale; pVertices[3].z=0.0f; pVertices[3].u=0.0f; pVertices[3].v=fScaleV; pVertices[3].oow=1.0f; pVertices[3].diffuse=0x00FFFFFF;

    SM_D3d::Device()->SetVertexShader(FVF_POSRHWDIFFUSETEX1);
    SM_D3d::SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);  
    SM_D3d::SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);  
    SM_D3d::SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
    SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);                        
 
    SM_D3d::SetTextureStageState(0, D3DTSS_COLOROP   , D3DTOP_SELECTARG1);
    SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG1 , D3DTA_TEXTURE );

    SM_D3d::Device()->DrawIndexedPrimitiveUP(
        D3DPT_TRIANGLELIST, 
        0,
        6,
        2,
        pIndices,
        D3DFMT_INDEX16,
        pVertices, sizeof(FVF_PosRhwDiffuseTex1));

    
    int i;

    for (i=0 ; i<0 ; i++)
    {
      SM_D3d::Device()->DrawIndexedPrimitiveUP(
        D3DPT_TRIANGLELIST, 
        0,
        6,
        2,
        pIndices,
        D3DFMT_INDEX16,
        pVertices, sizeof(FVF_PosRhwDiffuseTex1));

      fScale  =1.015f+1*sinf(fTime+i);
      
      pVertices[0].x=fxCenter-fxWidth*fScale; pVertices[0].y=fyCenter-fyHeight*fScale ; pVertices[0].z=0.0f; pVertices[0].u=0.0f; pVertices[0].v=0.0f; pVertices[0].oow=1.0f; pVertices[0].diffuse=0xFFFFFFFF;
      pVertices[1].x=fxCenter+fxWidth*fScale; pVertices[1].y=fyCenter-fyHeight*fScale ; pVertices[1].z=0.0f; pVertices[1].u=fScaleU; pVertices[1].v=0.0f; pVertices[1].oow=1.0f; pVertices[1].diffuse=0x00FFFFFF;
      pVertices[2].x=fxCenter+fxWidth*fScale; pVertices[2].y=fyCenter+fyHeight*fScale; pVertices[2].z=0.0f; pVertices[2].u=fScaleU; pVertices[2].v=fScaleV; pVertices[2].oow=1.0f; pVertices[2].diffuse=0xFFFFFFFF;
      pVertices[3].x=fxCenter-fxWidth*fScale; pVertices[3].y=fyCenter+fyHeight*fScale; pVertices[3].z=0.0f; pVertices[3].u=0.0f; pVertices[3].v=fScaleV; pVertices[3].oow=1.0f; pVertices[3].diffuse=0x00FFFFFF;

    
      SM_D3d::SetTextureStageState(0, D3DTSS_COLOROP   , D3DTOP_MODULATE);
      SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG1 , D3DTA_TEXTURE );
      SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG2 , D3DTA_TFACTOR);

      unsigned uColor=(5-i)*10;
      uColor=uColor | (uColor<<8) | (uColor<<16);
      SM_D3d::SetRenderState(D3DRS_TEXTUREFACTOR, uColor);

      SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);                
      SM_D3d::SetRenderState(D3DRS_SRCBLEND , D3DBLEND_ONE);
      SM_D3d::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);  

    
      SM_D3d::Device()->DrawIndexedPrimitiveUP(
        D3DPT_TRIANGLELIST, 
        0,
        6,
        2,
        pIndices,
        D3DFMT_INDEX16,
        pVertices, sizeof(FVF_PosRhwDiffuseTex1));
    }

  */
  }

  return (1);
  
}

int Escena3D::Command           (float fTime, const char* pcCommand)
{
  SM_DemoEffect::Command(fTime, pcCommand);

  char* pcCopy =0;
  char* pcToken;
  int   iReturn=-1;
    
  
  pcCopy=new char[strlen(pcCommand)+1];
  strcpy(pcCopy, pcCommand);

  pcToken=strtok(pcCopy, " \t");

  if (strcmp(pcToken, "LOAD")==0)
  {
    assert(!"This is now done with FXLOAD!!!\n");
  }
  else
  if (strcmp(pcToken, "SHOW")==0)
  {
    m_bVisible=true;
  }
  else
  if (strcmp(pcToken, "HIDE")==0)
  {
    m_bVisible=false;
  }
  else 
  if (strcmp(pcToken, "SETTIME")==0)
  {
    pcToken=strtok(0, " \t");
    float fNewTime=(float) atof(pcToken);

    m_MaxScene.SetStartTime(m_MaxScene.m_fStartTime-fNewTime);    
  }
  else 
  if (strcmp(pcToken, "SETABSOLUTETIME")==0)
  {
    pcToken=strtok(0, " \t");
    float fNewTime=(float) atof(pcToken);

    m_MaxScene.SetStartTime(fTime);
    m_MaxScene.SetAnimationOffset(fNewTime);
  }
  else 
  if (strcmp(pcToken, "SETSPEED")==0)
  {
    pcToken=strtok(0, " \t");
    float fSpeed=(float) atof(pcToken);

    m_MaxScene.SetSpeed(fSpeed);    
  }
  else 
  if (strcmp(pcToken, "CAMERA")==0)
  {
    pcToken=strtok(0, " \t");
    
    m_MaxScene.SetCamera(pcToken);
  }
  else if (strcmp(pcToken, "VERTEXCOLORS")==0)
  {
    pcToken=strtok(0, " \t");

    if (strcmp(pcToken, "ON")==0)
    {
      m_MaxScene.m_bVertexColors = true;
    }
    else
    {
      m_MaxScene.m_bVertexColors = false;
    }
  }
  else if (strcmp(pcToken, "FOG")==0)
  {
    pcToken=strtok(0, " \t");

    if (strcmp(pcToken, "ON")==0)
    {
      m_MaxScene.m_bFog=true;


      pcToken=strtok(0, " \t");
      m_MaxScene.m_fFogNear=(float) atof(pcToken);

      pcToken=strtok(0, " \t");
      m_MaxScene.m_fFogFar=(float) atof(pcToken);

      pcToken=strtok(0, " \t");        
      float fRed=(float) atof(pcToken);
      pcToken=strtok(0, " \t");        
      float fGreen=(float) atof(pcToken);
      pcToken=strtok(0, " \t");        
      float fBlue=(float) atof(pcToken);


      m_MaxScene.m_uColor=(int(fRed  *255.0f)<<16) |
                          (int(fGreen*255.0f)<<8)  |
                          (int(fBlue*255.0f)<<0);        

    }
    else
    {
      m_MaxScene.m_bFog=false;
    }
  }
  else if (strcmp(pcToken, "VIEWPORT")==0)
  {
    pcToken=strtok(0, " \t");
    m_VBx=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBy=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBw=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBh=(float) atof(pcToken);                   
  }
  else if (strcmp(pcToken, "VIEWPORTMORPH")==0)
  {
    m_VAx=m_VBx; m_VAy=m_VBy;  m_VAw=m_VBw, m_VAh=m_VBh;

    pcToken=strtok(0, " \t");
    m_VBx=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBy=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBw=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_VBh=(float) atof(pcToken);                  

    pcToken=strtok(0, " \t");
    float fLength=(float) atof(pcToken);                  

    m_ViewportSlider.Init(fLength);
    m_ViewportSlider.Start(fTime);
    m_bViewportTransition=true;           
  }
  else if (strcmp(pcToken, "NOISE")==0)
  {
    pcToken=strtok(0, " \t");
    m_MaxScene.m_fNoiseX=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_MaxScene.m_fNoiseY=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_MaxScene.m_fNoiseZ=(float) atof(pcToken);
    pcToken=strtok(0, " \t");
    m_MaxScene.m_fNoiseDuration=(float) atof(pcToken);                  
    m_MaxScene.m_fNoiseStartTime=fTime;
  }
  else if (strcmp(pcToken, "FORWARD")==0)
  {

    m_fForwardLength=1.0f;
    m_fStartForward =Timer::GetTime();           
  }
  else if (strcmp(pcToken, "FLIPX") == 0)
  {
    pcToken=strtok(0, " \t");

    if (strcmp(pcToken, "ON")==0)
    {
      m_MaxScene.m_bFlipX = true;
    }
    else
    {
      m_MaxScene.m_bFlipX = false;
    }
  }
  else if (strcmp(pcToken, "FLIPY") == 0)
  {
    pcToken=strtok(0, " \t");

    if (strcmp(pcToken, "ON")==0)
    {
      m_MaxScene.m_bFlipY = true;
    }
    else
    {
      m_MaxScene.m_bFlipY = false;
    }
  }
  else if (strcmp(pcToken, "SHADOWS") == 0)
  {
    pcToken=strtok(0, " \t");

    if (strcmp(pcToken, "ON")==0)
    {
      m_MaxScene.m_bRenderShadows = true;
    }
    else
    {
      m_MaxScene.m_bRenderShadows = false;
    }
  }
  else if (strcmp(pcToken, "PARTICLEPARAMS") == 0)
  {
    char* pcName  =strtok(0, " \t");
    char* pcParams=strtok(0, "\0");

    m_MaxScene.SetParticleSystemParams(pcName, pcParams);  
  }
  else if (strcmp(pcToken, "BEATFORWARD") == 0)
  {
    pcToken=strtok(0, " \t");

    if (pcToken && strcmp(pcToken, "OFF") == 0)
    {
      m_bBeatForward = false;
    }
    else
    {
      m_bBeatForward = true;
      m_fBeatForward = SafeAtof(pcToken);
    }
  }
  
  iReturn  = 0;

  if (pcCopy) { delete[] pcCopy; pcCopy=0; }
  return iReturn;
}  

MaxScene* Escena3D::GetScene()
{
  return (&m_MaxScene);
}


DEFINE_EFFECT(Escena3DFX)

Escena3D Efecto00("ESCENA_00");
Escena3D Efecto01("ESCENA_01");
Escena3D Efecto02("ESCENA_02");
Escena3D Efecto03("ESCENA_03");
Escena3D Efecto04("ESCENA_04");
Escena3D Efecto05("ESCENA_05");
Escena3D Efecto06("ESCENA_06");
Escena3D Efecto07("ESCENA_07");
Escena3D Efecto08("ESCENA_08");
Escena3D Efecto09("ESCENA_09");
Escena3D Efecto10("ESCENA_10");
Escena3D Efecto11("ESCENA_11");
Escena3D Efecto12("ESCENA_12");
Escena3D Efecto13("ESCENA_13");
Escena3D Efecto14("ESCENA_14");
Escena3D Efecto15("ESCENA_15");
Escena3D Efecto16("ESCENA_16");
Escena3D Efecto17("ESCENA_17");
Escena3D Efecto18("ESCENA_18");
Escena3D Efecto19("ESCENA_19");
Escena3D Efecto20("ESCENA_20");
Escena3D Efecto21("ESCENA_21");
Escena3D Efecto22("ESCENA_22");
Escena3D Efecto23("ESCENA_23");
Escena3D Efecto24("ESCENA_24");
Escena3D Efecto25("ESCENA_25");
Escena3D Efecto26("ESCENA_26");
Escena3D Efecto27("ESCENA_27");
Escena3D Efecto28("ESCENA_28");
Escena3D Efecto29("ESCENA_29");
Escena3D Efecto30("ESCENA_30");
Escena3D Efecto31("ESCENA_31");
