#include "SM_Engine3DPCH.h"
#include "SM_Mesh.h"
#include "SM_MaxScene.h"
#include "SM_D3DMesh.h"
#include "SM_D3DLight.h"
#include "SM_KeyFrame.h"
#include "SM_KeyFrameSequence.h"
#include "SM_ScalarSequence.h"
#include "MSystemFunctions.h"
#include "SM_FileVer.h"
#include "SM_VertexShader.h"
#include "SM_ParticleSystem.h"
#include "SM_GeomMorpher.h"
#include "SM_FFTBall.h"
#include "SM_DistortBall.h"
#include "SM_SpikeTube.h"
#include "SM_Metaballs.h"
#include "SM_Twister.h"


// Version 2: Animacion de FOV

int   iActualFileVer=-1;
int iFPS=30;

int GetOpenFileVer()
{
  return iActualFileVer;
}


void MaxCamera::SetScalarSequence(ScalarSequence* pSequence)
{
  m_pScalarSequence=pSequence;
}

void MaxCamera::SetStartTime(float fTime)
{
  IKFAnimable::SetStartTime(fTime);
  m_fScalarSequenceStartTime=fTime;
}
  

int MaxCamera::Load(MVFSFILE* f)
{
  if (MVFS::fread(&m_KeyFrame, sizeof(m_KeyFrame), 1, f)!=1) return -1;
  if (MVFS::fread(&m_fFOV, sizeof(m_fFOV), 1, f)!=1) return -1;
  if (MVFS::fread(&m_fNear, sizeof(m_fNear), 1, f)!=1) return -1;
  if (MVFS::fread(&m_fFar, sizeof(m_fFar), 1, f)!=1) return -1;
  if (MVFS::fread(m_pcName, sizeof(m_pcName), 1, f)!=1) return -1;
  

  return 0;
}

int MaxCamera::Save(MVFSFILE* f)
{
  if (MVFS::fwrite(&m_KeyFrame, sizeof(m_KeyFrame), 1, f)!=1) return -1;
  if (MVFS::fwrite(&m_fFOV, sizeof(m_fFOV), 1, f)!=1) return -1;
  if (MVFS::fwrite(&m_fNear, sizeof(m_fNear), 1, f)!=1) return -1;
  if (MVFS::fwrite(&m_fFar, sizeof(m_fFar), 1, f)!=1) return -1;
  if (MVFS::fwrite(m_pcName, sizeof(m_pcName), 1, f)!=1) return -1;

  return 0;
}

MaxScene::LoadData::LoadData()
{
}

MaxScene::LoadData::~LoadData()
{
  Shutdown();
}

int MaxScene::LoadData::Init()
{
  return 0;
}

int MaxScene::LoadData::Shutdown()
{
  unsigned i;

  for (i=0 ; i<m_Meshes.size() ; i++)
  {
    // FIXME when there is a separate geometry database
    delete m_Meshes[i]->GetGeometry();
    delete m_Meshes[i];
  }
  m_Meshes.clear();

  for (i=0 ; i<m_Cameras.size() ; i++)
  {
    delete m_Cameras[i];
  }
  m_Cameras.clear();

  for (i=0 ; i<m_MeshObjects.size() ; i++)
  {
    delete m_MeshObjects[i].m_pRenderMesh;
  }
  m_MeshObjects.clear();

  
  for (i=0 ; i<m_KeyFrames.size() ; i++)
  {
    delete m_KeyFrames[i];
  }
  m_KeyFrames.clear();


  for (i=0 ; i<m_Lights.size() ; i++)
  {
    delete m_Lights[i];
  }
  m_Lights.clear();


  for (i=0 ; i<m_Textures.size() ; i++)
  {
    delete m_Textures[i]->m_pcTextureName;
    delete m_Textures[i];
  }
  m_Textures.clear();

  for (i=0 ; i<m_Materials.size() ; i++)
  {
    if (m_Materials[i]->m_iShaderID!=-1)
    {
      ShaderManager::ReleaseShader(m_Materials[i]->m_iShaderID);
    }
    delete m_Materials[i];
  }
  m_Materials.clear();

  m_IDToMesh.clear();
  m_IDToCamera.clear();  
  m_IDToTexture.clear();  
  m_IDToMaterial.clear();  
  

  return 0;
}

void MaxScene::ResetStatus()
{
  m_pKeyFrames=0;
  m_pLights=0;
  m_pCameras=0;
  m_pMeshes=0;
  m_uMeshes=
  m_uLights=
  m_uCameras=
  m_uKeyFrames=0;
  m_iCamera=0;  

  m_bFog =false;
  m_bVertexColors=false;
  m_fFogNear=0.0f;
  m_fFogFar=1.0f;
  m_uColor=0xFFFFFFFF;
  m_fSpeed = 1.0;
  m_bRenderShadows = false;

  m_fX=0;
  m_fY=0;
  m_fWidth=640;
  m_fHeight=480;

  m_fNoiseX=m_fNoiseY=m_fNoiseZ=  0.0f;
  m_fNoiseStartTime=m_fNoiseDuration=0.0f;

  m_fOffsetTime = 0.0f;  
}

void MaxScene::Reset()
{
  m_bFog          = m_bVertexColors = false;
  m_bFlipX        = m_bFlipY = false;
  m_fSpeed        = 1.0f;
  m_fOffsetTime   = 0.0f;  
  m_iCamera       = 0;
  m_bRenderShadows= false;

  int iIterator;
  MBSL_FOREACH(m_ParticleSystems, iIterator)
  {
    RenderParticleSystem* pPS;
    MBSL_ELEMENT(m_ParticleSystems, iIterator, pPS);

    pPS->Reset();    
  }

  MBSL_FOREACH(m_GeomMorphers, iIterator)
  {
    SM_GeomMorpher* pGM;
    MBSL_ELEMENT(m_GeomMorphers, iIterator, pGM);

    pGM->Reset();    
  }  

  MBSL_FOREACH(m_FFTBalls, iIterator)
  {
    SM_FFTBall* pGM;
    MBSL_ELEMENT(m_FFTBalls, iIterator, pGM);

    pGM->Reset();    
  }  
  
}



MaxScene::MaxScene()
{ 
  ResetStatus();
}

MaxScene::~MaxScene()
{
  Shutdown();
}
  
int  MaxScene::Init()
{
  if (m_ParticleSystems.Init() != 0)
  {
    return -1;
  }

  if (m_GeomMorphers.Init() != 0)
  {
    return -1;
  }

  if (m_Metaballs.Init() != 0)
  {
    return -1;
  }

  if (m_DistortBalls.Init() != 0)
  {
	return -1;
  }

  if (m_SpikeTubes.Init() != 0)
  {
	return -1;
  }

  if (m_FFTBalls.Init() != 0)
  {
    return -1;
  }

  if (m_Twisters.Init() != 0)
  {
    return -1;
  }
  
  return (0);
}

int  MaxScene::Shutdown    ()
{
  unsigned i;
    
  if (m_pKeyFrames) { delete[] m_pKeyFrames; m_pKeyFrames=0; }
  if (m_pScalars)   { delete[] m_pScalars;    m_pScalars=0; }
  if (m_pLights)    { delete[] m_pLights;    m_pLights   =0; }
  if (m_pCameras)   { delete[] m_pCameras;    m_pCameras  =0; }

  for (i=0 ; i<m_uMeshes ; i++)
  {
    // FIXME when there is a separate geometry database
    delete m_pMeshes[i].GetGeometry();    
  }

  if (m_pMeshes)   { delete[] m_pMeshes;    m_pMeshes  =0; }

  int iIterator;

  MBSL_FOREACH(m_ParticleSystems, iIterator)
  {
    RenderParticleSystem* pPS;
    MBSL_ELEMENT(m_ParticleSystems, iIterator, pPS);
    delete pPS;
  }
  m_ParticleSystems.Shutdown();

  MBSL_FOREACH(m_GeomMorphers, iIterator)
  {
    SM_GeomMorpher* pGM;
    MBSL_ELEMENT(m_GeomMorphers, iIterator, pGM);

    delete pGM;
  }

  MBSL_FOREACH(m_FFTBalls, iIterator)
  {
    SM_FFTBall* pGM;
    MBSL_ELEMENT(m_FFTBalls, iIterator, pGM);

    delete pGM;    
  }  

  m_GeomMorphers.Shutdown();
  m_FFTBalls.Shutdown();  
  m_Metaballs.Shutdown();

  MBSL_FOREACH(m_DistortBalls, iIterator)
  {
    SM_DistortBall* pDB;
    MBSL_ELEMENT(m_DistortBalls, iIterator, pDB);

    delete pDB;
  }
  m_DistortBalls.Shutdown();
  
  MBSL_FOREACH(m_SpikeTubes, iIterator)
  {
    SM_SpikeTube* pDB;
    MBSL_ELEMENT(m_SpikeTubes, iIterator, pDB);

    delete pDB;
  }
  m_SpikeTubes.Shutdown();

  MBSL_FOREACH(m_Twisters, iIterator)
  {
    SM_Twister* pDB;
    MBSL_ELEMENT(m_Twisters, iIterator, pDB);

    delete pDB;
  }
  m_Twisters.Shutdown();

  

  ResetStatus();
     
  return (0);
}

void MaxScene::UpdateTimes()
{
  unsigned i;
  for (i=0 ; i<m_uMeshes ; i++)
  {
    m_pMeshes[i].SetStartTime(m_fStartTime);
  }

  for (i=0 ; i<m_uLights ; i++)
  {
    m_pLights[i].SetStartTime(m_fStartTime);
  }

  for (i=0 ; i<m_uCameras ; i++)
  {
    m_pCameras[i].SetStartTime(m_fStartTime);
  }
}

void MaxScene::SetStartTime(float fTime)
{
  m_fStartTime=fTime;
  UpdateTimes(); 
}

void MaxScene::SetAnimationOffset(float fTime)
{  
  m_fOffsetTime=fTime;
  UpdateTimes(); 
}


void MaxScene::SetSpeed(float fSpeed)
{
  float fCurrent = m_fOffsetTime + (Timer::GetTime() - m_fStartTime)*m_fSpeed;
  SetStartTime(Timer::GetTime());
  SetAnimationOffset(fCurrent);
  m_fSpeed = fSpeed;  
}


void MaxScene::AssignController(int iID, KeyFrameSequence* pKeyFrameSequence, LoadData* pData)
{
  std::map<int, int>::iterator iterMeshes;
  iterMeshes=pData->m_IDToMesh.find(iID);

  if (iterMeshes!=pData->m_IDToMesh.end())
  {
    pData->m_Meshes[pData->m_IDToMesh[iID]]->SetKeyFrameSequence(pKeyFrameSequence);
  }

  std::map<int, int>::iterator iterViewport;
  iterViewport=pData->m_IDToCamera.find(iID);

  if (iterViewport!=pData->m_IDToCamera.end())
  {
    pData->m_Cameras[pData->m_IDToCamera[iID]]->SetKeyFrameSequence(pKeyFrameSequence);
  }  

  std::map<int, int>::iterator iterLight;
  iterLight=pData->m_IDToLight.find(iID);

  if (iterLight!=pData->m_IDToLight.end())
  {
    pData->m_Lights[pData->m_IDToLight[iID]]->SetKeyFrameSequence(pKeyFrameSequence);
  }  
}

void MaxScene::AssignScalarController(int iID, ScalarSequence* pScalarSequence, LoadData* pData)
{
  
  std::map<int, int>::iterator iterViewport;
  iterViewport=pData->m_IDToCamera.find(iID);

  if (iterViewport!=pData->m_IDToCamera.end())
  {
    pData->m_Cameras[pData->m_IDToCamera[iID]]->SetScalarSequence(pScalarSequence);
  }    
}


#ifdef MAXSCENE_IMPORTER

int  MaxScene::LoadTextures (MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;
  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    if (pSceneRoot->m_Sons[i]->IsTag("TEXTURE"))
    {
      MSurface s;

      char pcBaseName[MVFSMAX_PATH];
     
      MExtractBasename(pcBaseName, pSceneRoot->m_Sons[i]->GetSon("FILE")->m_Sons[0]->m_Token.m_pszString);

      void MExtractBasename(char* pcBasename, const char* pcPathFile);
      
      // Add ID to hash table
      MaxTexture* pTexture=new MaxTexture;
      if (!pTexture)
      {
        return (-1);
      }

      pTexture->m_pcTextureName=new char[strlen(pcBaseName)+1];
      if (!pTexture->m_pcTextureName)
      {
        return (-1);
      }

      // Copy texture name
      strcpy(pTexture->m_pcTextureName, pcBaseName);
      
      // Add to containers      
      int iID;
      GetInt(pSceneRoot->m_Sons[i]->GetSon("ID"), &iID);        

      pData->m_IDToTexture.insert(std::pair<int, int>(iID, pData->m_Textures.size()));
      pData->m_Textures.push_back(pTexture);
      
    }
  }

  return (0);
}


int  MaxScene::LoadMaterials(MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;
  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    if (pSceneRoot->m_Sons[i]->IsTag("MATERIAL"))
    {
      MetaFileNode* pMaterialNode   =pSceneRoot->m_Sons[i];

      int iDiffuseID, iReflectionID;
      
      MaxMaterial* pMaxMaterial=new MaxMaterial;


      if (ShaderManager::FindShader(pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString)!=-1)
      {
        pMaxMaterial->m_iShaderID=ShaderManager::LoadShader(pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString);
      }
      else
      {
        iDiffuseID   =pMaterialNode->GetSon("DIFFUSETEXTUREID")->m_Sons[0]->m_Token.m_iValue;      
        iReflectionID=pMaterialNode->GetSon("REFLECTIONTEXTUREID")->m_Sons[0]->m_Token.m_iValue;      

        if (iDiffuseID!=-1)
        {
          // Diffuse
          if (iReflectionID==-1)
          {
            assert(pData->m_IDToTexture.find(iDiffuseID)!=pData->m_IDToTexture.end());
            pMaxMaterial->m_iShaderID=ShaderManager::LoadCommonShader(
              pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString, 
              ShaderManager::ST_STANDARDTEXTURE, 
              pData->m_Textures[pData->m_IDToTexture[iDiffuseID]]->m_pcTextureName,
              0);
          }
          else
          {
            // Diffuse+Environment
            assert(pData->m_IDToTexture.find(iDiffuseID)!=pData->m_IDToTexture.end());
            pMaxMaterial->m_iShaderID=ShaderManager::LoadCommonShader(
              pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString, 
              ShaderManager::ST_STANDARDTEXTUREWITHREFLECTION, 
              pData->m_Textures[pData->m_IDToTexture[iDiffuseID]]->m_pcTextureName,
              pData->m_Textures[pData->m_IDToTexture[iReflectionID]]->m_pcTextureName);
          }
        }
        else if (iReflectionID!=-1)
        {
          assert(pData->m_IDToTexture.find(iReflectionID)!=pData->m_IDToTexture.end());
            pMaxMaterial->m_iShaderID=ShaderManager::LoadCommonShader(
              pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString, 
              ShaderManager::ST_STANDARDREFLECTION, 
              pData->m_Textures[pData->m_IDToTexture[iReflectionID]]->m_pcTextureName,
              0);        
        }
        else
        {
          float r=pMaterialNode->GetSon("DIFFUSECOLOR")->m_Sons[0]->m_Token.m_fValue;
          float g=pMaterialNode->GetSon("DIFFUSECOLOR")->m_Sons[1]->m_Token.m_fValue;
          float b=pMaterialNode->GetSon("DIFFUSECOLOR")->m_Sons[2]->m_Token.m_fValue;

          pMaxMaterial->m_iShaderID=ShaderManager::LoadCommonShader(
            pMaterialNode->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString, 
            ShaderManager::ST_PLAINCOLOR, 
            0,
            0,
            (int(r*255.0f)<<16) | (int(g*255.0f)<<8) | (int(b*255.0f)));          
        }
      }
      
      int iID;
      GetInt(pSceneRoot->m_Sons[i]->GetSon("ID"), &iID);        

      pData->m_IDToMaterial.insert(std::pair<int, int>(iID, pData->m_Materials.size()));
      pData->m_Materials.push_back(pMaxMaterial);            
    }
  }

  return (0);  
}
  

int  MaxScene::LoadControllers(MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;

  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    if (pSceneRoot->m_Sons[i]->IsTag("CONTROLLER"))
    {
      if (strcmp(pSceneRoot->m_Sons[i]->GetSon("TYPE")->m_Sons[0]->m_Token.m_pszString,
                 "POSROT")==0)
      {
        KeyFrameSequence* pKeyFrameSequence=new KeyFrameSequence;
        if (!pKeyFrameSequence)
        {
          return (-1);
        }

        GetKeyFrameSequence(pSceneRoot->m_Sons[i]->GetSon("DATA")->GetSon("SAMPLES"), pKeyFrameSequence);

        int iID;
        GetInt(pSceneRoot->m_Sons[i]->GetSon("OWNERID"), &iID);        
        AssignController(iID, pKeyFrameSequence, pData);        

        pData->m_KeyFrames.push_back(pKeyFrameSequence);
        pData->m_ControllerIndexToID.push_back(iID);
      }
      else if (strcmp(pSceneRoot->m_Sons[i]->GetSon("TYPE")->m_Sons[0]->m_Token.m_pszString,
                 "FLOAT")==0)
      {
        ScalarSequence* pScalarSequence=new ScalarSequence;
        if (!pScalarSequence)
        {
          return (-1);
        }

        GetScalarSequence(pSceneRoot->m_Sons[i]->GetSon("DATA")->GetSon("SAMPLES"), pScalarSequence);

        int iID;
        GetInt(pSceneRoot->m_Sons[i]->GetSon("OWNERID"), &iID);        
        AssignScalarController(iID, pScalarSequence, pData);        

        pData->m_Scalars.push_back(pScalarSequence);
        pData->m_ScalarControllerIndexToID.push_back(iID);
      }
    }
  }

  return (0);
}

int  MaxScene::LoadCameras(MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;
  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    if (pSceneRoot->m_Sons[i]->IsTag("CAMERA"))
    {
      MaxCamera* pCamera=new MaxCamera;
      if (!pCamera)
      {
        return (-1);
      }

      Vector3D    v3dPosition;
      Quaternion  qRotation;

      GetVector3D   (pSceneRoot->m_Sons[i]->GetSon("POSITION"), &pCamera->m_KeyFrame.m_Position);
      GetQuaternion (pSceneRoot->m_Sons[i]->GetSon("ROTATION"), &pCamera->m_KeyFrame.m_Rotation);

      GetFloat(pSceneRoot->m_Sons[i]->GetSon("FOV"), &pCamera->m_fFOV);
      GetFloat(pSceneRoot->m_Sons[i]->GetSon("NEAR"), &pCamera->m_fNear);
      GetFloat(pSceneRoot->m_Sons[i]->GetSon("FAR"), &pCamera->m_fFar);
      
      if (pSceneRoot->m_Sons[i]->GetSon("NAME"))
      {
        strcpy(pCamera->m_pcName, pSceneRoot->m_Sons[i]->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString);
      }
      else
      {
        pCamera->m_pcName[0]=0;
      }
      
      int iID;
      GetInt(pSceneRoot->m_Sons[i]->GetSon("ID"), &iID);     

      // Add id->pointer mapping
      pData->m_IDToCamera.insert(std::pair<int, int>(iID, pData->m_Cameras.size()));
      pData->m_Cameras.push_back(pCamera);

    }
  }
  return (0);
}

int  MaxScene::LoadLights(MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;
  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    SM_Main::OutputConsole("%s\n",pSceneRoot->m_Sons[i]->m_Token.m_pszString);
    if (pSceneRoot->m_Sons[i]->IsTag("LIGHT"))
    {
      
      D3DLight* pLight=new D3DLight;
      if (!pLight)
      {
        return (-1);
      }
      
      Vector3D v3d;        
      pLight->SetPosition(GetVector3D(pSceneRoot->m_Sons[i]->GetSon("POSITION"), &v3d));

      

      // Color
      MetaFileNode* pColor=pSceneRoot->m_Sons[i]->GetSon("COLOR");
      float r,g,b;
      r=g=b=1.0f;
      if (pColor)
      {
        r=pColor->m_Sons[0]->m_Token.m_fValue;
        g=pColor->m_Sons[1]->m_Token.m_fValue;
        b=pColor->m_Sons[2]->m_Token.m_fValue;
      }
      
      if (!strcmp(pSceneRoot->m_Sons[i]->GetSon("TYPE")->m_Sons[0]->m_Token.m_pszString, "OMNI"))
      {
        pLight->GetLight()->Type     =D3DLIGHT_POINT;
      }
      else if  (!strcmp(pSceneRoot->m_Sons[i]->GetSon("TYPE")->m_Sons[0]->m_Token.m_pszString, "DIRECTIONAL") || 
                !strcmp(pSceneRoot->m_Sons[i]->GetSon("TYPE")->m_Sons[0]->m_Token.m_pszString, "TDIRECTIONAL"))
    
      {
        Quaternion qRot;
      
        GetQuaternion(pSceneRoot->m_Sons[i]->GetSon("ROTATION"), &qRot);
        qRot=qRot*Quaternion(0.5f*3.141592f, Vector3D(1.0f, 0.0f, 0.0f));
        pLight->SetRotation(&qRot);        
      
        float R[3][3];
        qRot.ToRotationMatrix(R);
        pLight->GetLight()->Type     =D3DLIGHT_DIRECTIONAL;    
        pLight->GetLight()->Direction.x = -R[0][0];//R[2][0];
        pLight->GetLight()->Direction.y = -R[1][0];//R[2][1];
        pLight->GetLight()->Direction.z = -R[2][0];//R[2][2];
      }
      else
      {
        pLight->GetLight()->Type     =D3DLIGHT_POINT;
      }
      
      //pLight->GetLight()->
      if (pSceneRoot->GetSon("SCENEINFO")->GetSon("AMBIENT"))
      {
        pLight->GetLight()->Ambient.a   =0.0f;
        pLight->GetLight()->Ambient.r   =pSceneRoot->GetSon("SCENEINFO")->GetSon("AMBIENT")->m_Sons[0]->m_Token.m_fValue;
        pLight->GetLight()->Ambient.g   =pSceneRoot->GetSon("SCENEINFO")->GetSon("AMBIENT")->m_Sons[1]->m_Token.m_fValue;
        pLight->GetLight()->Ambient.b   =pSceneRoot->GetSon("SCENEINFO")->GetSon("AMBIENT")->m_Sons[2]->m_Token.m_fValue;
      }
      else
      {
        pLight->GetLight()->Ambient.a   =0.0f;
        pLight->GetLight()->Ambient.r   =0.0f;
        pLight->GetLight()->Ambient.g   =0.0f;
        pLight->GetLight()->Ambient.b   =0.0f;
      }

      

      float fMultiplier =1.0f;
      float fAttenuation=0.0f;

      if (pSceneRoot->m_Sons[i]->GetSon("MULTIPLIER"))
      {
        fMultiplier=pSceneRoot->m_Sons[i]->GetSon("MULTIPLIER")->m_Sons[0]->m_Token.m_fValue;
      }

      if (pSceneRoot->m_Sons[i]->GetSon("FARATTENUATION"))
      {
        fAttenuation=pSceneRoot->m_Sons[i]->GetSon("FARATTENUATION")->m_Sons[0]->m_Token.m_fValue;
      }
      
     
      if (fAttenuation)
      {
        pLight->GetLight()->Attenuation0=0.0f;
        pLight->GetLight()->Attenuation1=(1.0f/(fMultiplier))*1.0f/(0.15f*fAttenuation);
        pLight->GetLight()->Attenuation2=0.0f;
      }
      else
      {
        pLight->GetLight()->Attenuation0=1.0f/fMultiplier;
        pLight->GetLight()->Attenuation1=0.0f;
        pLight->GetLight()->Attenuation2=0.0f;
      }
      pLight->GetLight()->Range       =1000000.0f;
      pLight->GetLight()->Diffuse.a   =pLight->GetLight()->Specular.a=0.0f;
      pLight->GetLight()->Diffuse.r=pLight->GetLight()->Specular.r=r;
      pLight->GetLight()->Diffuse.g=pLight->GetLight()->Specular.g=g;
      pLight->GetLight()->Diffuse.b=pLight->GetLight()->Specular.b=b;            
      
      
      int iID;
      GetInt(pSceneRoot->m_Sons[i]->GetSon("ID"), &iID);
      pData->m_IDToLight.insert(std::pair<int, int>(iID, pData->m_Lights.size()));      
      pData->m_Lights.push_back(pLight);

    }
  }

  return (0);
}

int  MaxScene::LoadMeshes(MetaFileNode* pSceneRoot, LoadData* pData)
{
  unsigned i;
  for (i=0 ; i<pSceneRoot->m_Sons.size() ; i++)
  {
    SM_Main::OutputConsole("%s\n",pSceneRoot->m_Sons[i]->m_Token.m_pszString);
    if (pSceneRoot->m_Sons[i]->IsTag("MESH"))
    {
      Mesh MyMesh;

      // Load generic mesh
      MetaFileNode* pNode=pSceneRoot->m_Sons[i]->GetSon("MAXMESH");
      if (MyMesh.Import(pNode)!=0)
      {
        return (-1);
      }

      if (MyMesh.m_Faces.size())
      {
        // Generate render data
        RenderMesh* pRenderMesh=new RenderMesh;
        if (MyMesh.GenerateRenderMesh(pRenderMesh)!=0)
        {
          delete pRenderMesh;
          return (-1);
        }

        unsigned j;

        char* pcName=new char[strlen(pSceneRoot->m_Sons[i]->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString)+1];
        if (!pcName)
        {
          return -1;
        }
        strcpy(pcName, pSceneRoot->m_Sons[i]->GetSon("NAME")->m_Sons[0]->m_Token.m_pszString);
        pRenderMesh->m_pcName=pcName;


        for (j=0 ; j<pRenderMesh->m_uElements ; j++)
        {
          const char* pcShaderName;


          if (pRenderMesh->m_pElements[j].m_iMaterial!=-1)
          {

            int iID       =pRenderMesh->m_pElements[j].m_iMaterial;
            int iMaterial =pData->m_IDToMaterial[iID];

            if (ShaderManager::GetShaderNameByID(
                pData->m_Materials[iMaterial]->m_iShaderID, 
                pcShaderName)!=0)
            {
              pRenderMesh->m_pElements[j].m_pcMaterial[0]=0;
            }
            else
            {
            strcpy(
              pRenderMesh->m_pElements[j].m_pcMaterial,
              pcShaderName);                      
            }
          }
          else
          {
            pRenderMesh->m_pElements[j].m_pcMaterial[0]=0;
          }
        }
       
        MeshObject newMeshObject;
        newMeshObject.m_pRenderMesh=pRenderMesh;

        // Generate D3D friendly mesh
        D3DMesh* pMesh=new D3DMesh;
        if (!pMesh)
        {
          return (-1);
        }

        D3DGeometry* pGeometry=new D3DGeometry;
        if (!pGeometry)
        {
          return (-1);
        }

        if (pGeometry->Init(pRenderMesh))
        {
          return (-1);
        }

        if (pMesh->Init()!=0)
        {
          return (-1);
        }

        int iID;
        GetInt(pSceneRoot->m_Sons[i]->GetSon("ID"), &iID);
       
        pData->m_IDToMesh.insert(std::pair<int, int>(iID, pData->m_Meshes.size()));


        // Assign Geometry
        pMesh->SetGeometry(pGeometry);

        Vector3D v3d;        
        Quaternion qRot;
        
        pMesh->SetPosition(GetVector3D(pSceneRoot->m_Sons[i]->GetSon("POSITION"), &v3d));
        GetQuaternion(pSceneRoot->m_Sons[i]->GetSon("ROTATION"), &qRot);        
        newMeshObject.m_PositionRotation.m_Position=v3d;
        newMeshObject.m_PositionRotation.m_Rotation=qRot;
        
        GetVector3D(pSceneRoot->m_Sons[i]->GetSon("PIVOTPOSITION"), &v3d);
        GetQuaternion(pSceneRoot->m_Sons[i]->GetSon("PIVOTROTATION"), &qRot);        
        newMeshObject.m_PivotPositionRotation.m_Position=v3d;
        newMeshObject.m_PivotPositionRotation.m_Rotation=qRot;
                                    
        // Add parent mesh for lookup
        if (pSceneRoot->m_Sons[i]->GetSon("PARENTID"))
        {
          GetInt(pSceneRoot->m_Sons[i]->GetSon("PARENTID"), &newMeshObject.m_iParent);
        }
      
        pData->m_MeshObjects.push_back(newMeshObject);        
        

        // Add mesh to list
        pData->m_Meshes.push_back(pMesh);


        for (j=0 ; j<pMesh->GetGeometry()->m_uMeshElements ; j++)
        {
          if (pMesh->GetGeometry()->m_pMeshElements[j].m_iShader==-1)
          {
            pMesh->GetGeometry()->m_pMeshElements[j].m_iShader=-1;
          }
          else
          {
            pMesh->GetGeometry()->m_pMeshElements[j].m_iShader=
              pData->m_Materials[
              pData->m_IDToMaterial[pMesh->GetGeometry()->m_pMeshElements[j].m_iShader]]->m_iShaderID;
          }
          
        }        
      }   
      
    }
  }

  for (i=0 ; i<pData->m_MeshObjects.size() ; i++)
  {
    if (pData->m_MeshObjects[i].m_iParent==0)
    {
      pData->m_MeshObjects[i].m_iParent=-1;
    }
    else
    {
      pData->m_MeshObjects[i].m_iParent=pData->m_IDToMesh[pData->m_MeshObjects[i].m_iParent];
    }    
  }
  

  return (0);
}

int MaxScene::SaveScalarControllersAssignment(MVFSFILE* f, LoadData* pData)
{
  unsigned i;

  for (i=0 ; i<pData->m_Scalars.size() ; i++)
  {
    int iType, iIndex=-1;
  
    int iID=pData->m_ScalarControllerIndexToID[i];


    std::map<int, int>::iterator iterViewport;
    iterViewport=pData->m_IDToCamera.find(iID);

    if (iterViewport!=pData->m_IDToCamera.end())
    {
      iIndex=pData->m_IDToCamera[iID];            
      iType = E_CAMERA;
    }  

    if (MVFS::fwrite(&iType , sizeof(int), 1, f)!=1) return -1;
    if (MVFS::fwrite(&iIndex, sizeof(int), 1, f)!=1) return -1;
  }

  return 0;
}

int MaxScene::SaveControllersAssignment(MVFSFILE* f, LoadData* pData)
{
  unsigned i;

  for (i=0 ; i<pData->m_KeyFrames.size() ; i++)
  {
    int iType, iIndex=-1;
  
    int iID=pData->m_ControllerIndexToID[i];

    std::map<int, int>::iterator iterMeshes;
    iterMeshes=pData->m_IDToMesh.find(iID);

    if (iterMeshes!=pData->m_IDToMesh.end())
    {
      iIndex=pData->m_IDToMesh[iID];      
      iType = E_MESH;
    }

    std::map<int, int>::iterator iterViewport;
    iterViewport=pData->m_IDToCamera.find(iID);

    if (iterViewport!=pData->m_IDToCamera.end())
    {
      iIndex=pData->m_IDToCamera[iID];            
      iType = E_CAMERA;
    }  

    std::map<int, int>::iterator iterLight;
    iterLight=pData->m_IDToLight.find(iID);

    if (iterLight!=pData->m_IDToLight.end())
    {
      iIndex=pData->m_IDToLight[iID];      
      iType = E_LIGHT;
    }  

    if (MVFS::fwrite(&iType , sizeof(int), 1, f)!=1) return -1;
    if (MVFS::fwrite(&iIndex, sizeof(int), 1, f)!=1) return -1;

  }

  return 0;
}



int  MaxScene::CompileML      (const char* pcMLFilename, MVFSFILE* f)
{
  MetaFile ML;

  LoadData LoadData;

  if (ML.Load(pcMLFilename)!=0)
  {
    SM_Main::OutputError("Error loading %s (doesn't exist?)", pcMLFilename);
    return (-1);
  }


  // Get scene node
  MetaFileNode* pSceneRoot;

  pSceneRoot=ML.Root()->GetSon("SCENE");
  if (!pSceneRoot)
  {
    SM_Main::OutputError("No <SCENE> node in %s ", pcMLFilename);
    return (-1);
  }


  iFPS=30;
  GetInt(pSceneRoot->GetSon("SCENEINFO")->GetSon("FRAMERATE"), &iFPS);
  
      

  // Load meshes
  if (LoadTextures(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading textures in %s ", pcMLFilename);
    return (-1);
  }

  if (LoadMaterials(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading materials in %s ", pcMLFilename);
    return (-1);
  }

  if (LoadMeshes(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading meshes in %s ", pcMLFilename);
    return (-1);
  }
  
  if (LoadCameras(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading cameras in %s ", pcMLFilename);
    return (-1);
  }

  if (LoadLights(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading lights in %s ", pcMLFilename);
    return (-1);
  }

  if (LoadControllers(pSceneRoot, &LoadData)==-1)
  {
    SM_Main::OutputError("Error loading controlers in %s ", pcMLFilename);
    return (-1);
  }

  if (LoadData.m_Cameras.size()==0)
  {  
    SM_Main::OutputError("Scene doesnt have a camera!!!");
    return (-1);
  }

   
 
  return (SaveBin(f, &LoadData));
}

int MaxScene::SaveBin(MVFSFILE* f, LoadData* pData)
{
  unsigned i;

  // Version
  if (MVFS::fwrite((void*)&MAXSCENE_FILEVER, sizeof(MAXSCENE_FILEVER), 1, f)!=1) return -1;

  // Save Meshes  
  i=pData->m_MeshObjects.size();
  if (MVFS::fwrite(&i, sizeof(i), 1, f)!=1) return -1;
  for (i=0 ; i<pData->m_MeshObjects.size() ; i++)
  {
    pData->m_MeshObjects[i].m_pRenderMesh->Save(f);

    if (MVFS::fwrite(&(pData->m_MeshObjects[i].m_PositionRotation), sizeof(KeyFrame), 1, f)!=1)
    {
      return -1;
    }

    if (MVFS::fwrite(&(pData->m_MeshObjects[i].m_PivotPositionRotation), sizeof(KeyFrame), 1, f)!=1)
    {
      return -1;
    }
    
    if (MVFS::fwrite(&(pData->m_MeshObjects[i].m_iParent), sizeof(int), 1, f)!=1)
    {
      return -1;
    }
  }

  
  

  // Save Lights  
  i=pData->m_Lights.size();
  if (MVFS::fwrite(&i, sizeof(i), 1, f)!=1) return -1;  
  for (i=0 ; i<pData->m_Lights.size() ; i++)
  {
    pData->m_Lights[i]->Save(f);
  }

  // Save Camreas
  i=pData->m_Cameras.size();
  if (MVFS::fwrite(&i, sizeof(i), 1, f)!=1) return -1;  
  for (i=0 ; i<pData->m_Cameras.size() ; i++)
  {
    pData->m_Cameras[i]->Save(f);
  }

  // Save Keyframes
  i=pData->m_KeyFrames.size();
  if (MVFS::fwrite(&i, sizeof(i), 1, f)!=1) return -1;  
  for (i=0 ; i<pData->m_KeyFrames.size() ; i++)
  {
    pData->m_KeyFrames[i]->Save(f);
  }

  SaveControllersAssignment(f, pData);


  // Save Keyframes
  i=pData->m_Scalars.size();
  if (MVFS::fwrite(&i, sizeof(i), 1, f)!=1) return -1;  
  for (i=0 ; i<pData->m_Scalars.size() ; i++)
  {
    pData->m_Scalars[i]->Save(f);
  }

  SaveScalarControllersAssignment(f, pData);



  return 0;
}


#endif

void MaxScene::ClearForShadow(RenderContext* pRenderContext)
{
  FVF_PosRhwDiffuseTex1 pVertices[4];
  unsigned short        pIndices[6]={0,1,2,1,2,3};

  float fX, fY, fWidth, fHeight;

  fX     =Coordinates::GetPhysicX(m_fX);
  fY     =Coordinates::GetPhysicY(m_fY);
  fWidth =Coordinates::GetPhysicX(m_fWidth);
  fHeight=Coordinates::GetPhysicY(m_fHeight);
  
  pVertices[0].x=fX       ; pVertices[0].y=fY        ; pVertices[0].oow=pVertices[0].z=1.0f; pVertices[0].u=pVertices[0].v=0.0f; pVertices[0].diffuse=0x40000000;
  pVertices[1].x=fX+fWidth; pVertices[1].y=fY        ; pVertices[1].oow=pVertices[1].z=1.0f; pVertices[1].u=pVertices[1].v=0.0f; pVertices[1].diffuse=0x40000000;
  pVertices[2].x=fX       ; pVertices[2].y=fY+fHeight; pVertices[2].oow=pVertices[2].z=1.0f; pVertices[2].u=pVertices[2].v=0.0f; pVertices[2].diffuse=0x40000000;
  pVertices[3].x=fX+fWidth; pVertices[3].y=fY+fHeight; pVertices[3].oow=pVertices[3].z=1.0f; pVertices[3].u=pVertices[3].v=0.0f; pVertices[3].diffuse=0x40000000;

  
  SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLOROP   , D3DTOP_SELECTARG1);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG1 , D3DTA_DIFFUSE);  
  
  SM_D3d::SetTextureStageState(0, D3DTSS_ALPHAOP   , D3DTOP_SELECTARG1);
  SM_D3d::SetTextureStageState(0, D3DTSS_ALPHAARG1 , D3DTA_DIFFUSE);  
  SM_D3d::SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  SM_D3d::SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
  SM_D3d::SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_TRUE);

  SM_D3d::SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
  SM_D3d::SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
  SM_D3d::SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL);
  SM_D3d::SetRenderState(D3DRS_STENCILREF, 0);
       

  SM_D3d::SetRenderState(D3DRS_COLORWRITEENABLE, 0xFFFFFFFF);
  SM_D3d::SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    
  SM_D3d::SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE );    
  SM_D3d::Device()->SetVertexShader(FVF_POSRHWDIFFUSETEX1);

  SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  SM_D3d::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  SM_D3d::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);  
  
  
  
  SM_D3d::Device()->DrawIndexedPrimitiveUP(
      D3DPT_TRIANGLELIST, 
      0,
      6,
      2,
      pIndices,
      D3DFMT_INDEX16,
      pVertices, sizeof(FVF_PosRhwDiffuseTex1)); 
  

  SM_D3d::SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
  SM_D3d::SetRenderState(D3DRS_STENCILENABLE, FALSE);        
}

void MaxScene::ClearZ(RenderContext* pRenderContext, bool bClearColor)
{
#if 1
  // Workaround for GForce bug
  FVF_PosRhwDiffuseTex1 pVertices[4];
  unsigned short        pIndices[6]={0,1,2,1,2,3};

  float fX, fY, fWidth, fHeight;

  fX     =Coordinates::GetPhysicX(m_fX);
  fY     =Coordinates::GetPhysicY(m_fY);
  fWidth =Coordinates::GetPhysicX(m_fWidth);
  fHeight=Coordinates::GetPhysicY(m_fHeight);
  
  pVertices[0].x=fX       ; pVertices[0].y=fY        ; pVertices[0].oow=pVertices[0].z=1.0f; pVertices[0].u=pVertices[0].v=0.0f; pVertices[0].diffuse=0xFF000000;
  pVertices[1].x=fX+fWidth; pVertices[1].y=fY        ; pVertices[1].oow=pVertices[1].z=1.0f; pVertices[1].u=pVertices[1].v=0.0f; pVertices[1].diffuse=0xFF000000;
  pVertices[2].x=fX       ; pVertices[2].y=fY+fHeight; pVertices[2].oow=pVertices[2].z=1.0f; pVertices[2].u=pVertices[2].v=0.0f; pVertices[2].diffuse=0xFF000000;
  pVertices[3].x=fX+fWidth; pVertices[3].y=fY+fHeight; pVertices[3].oow=pVertices[3].z=1.0f; pVertices[3].u=pVertices[3].v=0.0f; pVertices[3].diffuse=0xFF000000;

  
  SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLOROP   , D3DTOP_SELECTARG1);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG1 , D3DTA_DIFFUSE);  
  
  SM_D3d::SetTextureStageState(0, D3DTSS_ALPHAOP   , D3DTOP_SELECTARG1);
  SM_D3d::SetTextureStageState(0, D3DTSS_ALPHAARG1 , D3DTA_DIFFUSE);  
  SM_D3d::SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  SM_D3d::SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
  SM_D3d::SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_TRUE);

  if (!bClearColor)
  {
    SM_D3d::SetRenderState(D3DRS_COLORWRITEENABLE, 0);          
  }

  SM_D3d::SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE );    
  SM_D3d::Device()->SetVertexShader(FVF_POSRHWDIFFUSETEX1);
  
  
  SM_D3d::Device()->DrawIndexedPrimitiveUP(
      D3DPT_TRIANGLELIST, 
      0,
      6,
      2,
      pIndices,
      D3DFMT_INDEX16,
      pVertices, sizeof(FVF_PosRhwDiffuseTex1)); 


  SM_D3d::SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
  SM_D3d::SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
  SM_D3d::SetRenderState(D3DRS_COLORWRITEENABLE, 0xF);          
#else
  SM_D3d::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  SM_D3d::Device()->Clear(0, 0, D3DCLEAR_ZBUFFER | (bClearColor?D3DCLEAR_TARGET:0)  | (SM_D3d::GetCurrentMode()->bStencil?D3DCLEAR_STENCIL:0), 0xFF000000, 1.0f, 0.0f);
#endif 
}

void MaxScene::SetCamera         (const char* pcName)
{
  unsigned i;

  for (i=0 ; i<m_uCameras ; i++)
  {
    if (stricmp(pcName, m_pCameras[i].m_pcName)==0)
    {
      m_iCamera=i;
    }
  }
}


void MaxScene::Render(RenderContext* pRenderContext, int iOutcode)
{
  Render(pRenderContext, iOutcode, false);
}

void MaxScene::ClearCache()
{
  unsigned i;

  for (i = 0 ; i < m_uMeshes ; i++)
  {
    m_pMeshes[i].ClearCache();
  }      
}

void MaxScene::PreCache()
{
  unsigned i;

  for (i = 0 ; i < m_uMeshes ; i++)
  {
    m_pMeshes[i].PreCache();
  }      
}


void MaxScene::UpdateRC(RenderContext* pRC, float fTime)
{
  KeyFrame KeyFrameFinal;

  if (m_pCameras[m_iCamera].m_pKeyFrameSequence)
  {           
    m_pCameras[m_iCamera].m_pKeyFrameSequence->GetKeyFrame(fTime, m_fStartTime, &KeyFrameFinal);        
  }
  else
  {
    KeyFrameFinal=m_pCameras[m_iCamera].m_KeyFrame;    
  }

  KeyFrameFinal.m_Rotation=KeyFrameFinal.m_Rotation*Quaternion(0.5f*3.141592f, Vector3D(1.0f, 0.0f, 0.0f));

  // Noise de camara  
  Vector3D v3dNoise;

  float fNoiseAmplitude;
  if (m_fNoiseDuration)
  {
    float fOffset=(fTime-m_fNoiseStartTime)/m_fNoiseDuration;

    if (fOffset>=1.0f)
    {
      m_fNoiseX=m_fNoiseY=m_fNoiseZ=0.0f;
      m_fNoiseDuration=0.0f;
      fOffset=1.0f;
    }

    fNoiseAmplitude=1.0f-fOffset;
  }
  else
  {
    fNoiseAmplitude=1.0f;
  }
   
  Matrix3X3 Rot;
  ToTransform(&Rot, &KeyFrameFinal.m_Rotation);

  v3dNoise=(-1.0f+2.0f*fmodf(float(rand())/float(RAND_MAX), 1.0f))*m_fNoiseX*fNoiseAmplitude*Vector3D(Rot.m_11, Rot.m_12, Rot.m_13)+
           (-1.0f+2.0f*fmodf(float(rand())/float(RAND_MAX), 1.0f))*m_fNoiseY*fNoiseAmplitude*Vector3D(Rot.m_21, Rot.m_22, Rot.m_23)+
           (-1.0f+2.0f*fmodf(float(rand())/float(RAND_MAX), 1.0f))*m_fNoiseZ*fNoiseAmplitude*Vector3D(Rot.m_31, Rot.m_32, Rot.m_33);



  float fFOV;

  if (m_pCameras[m_iCamera].m_pScalarSequence)
  {
    m_pCameras[m_iCamera].m_pScalarSequence->GetScalar(fTime, m_fStartTime, &fFOV);
  }
  else
  {
    fFOV=m_pCameras[m_iCamera].m_fFOV;
  }

  pRC->Set(
    KeyFrameFinal.m_Position+v3dNoise,
    KeyFrameFinal.m_Rotation,
    fFOV,
    0.75f,
    m_pCameras[m_iCamera].m_fNear,
    m_pCameras[m_iCamera].m_fFar);

  pRC->SetViewport(m_fX, m_fY, m_fWidth, m_fHeight);  
  pRC->SyncRasterizer();

  // hack for flipx and flipy
  Matrix4X4 m;
  pRC->GetViewport()->ProjectionMatrix(m);
  if (m_bFlipX) m.m_11 *= -1.0f;
  if (m_bFlipY) m.m_22 *= -1.0f;
  SM_D3d::Device()->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&m);    
  

  pRC->UpdateFrustum();
}


void MaxScene::Render(RenderContext* pRenderContext, int iOutcode, bool bClearColor)
{
  RenderContext RC;

  if (!m_pCameras)
  {
    return;
  }

  RenderPipeline::Flush();

  float fFinalTime = GetSceneTime(Timer::GetTime());

  UpdateRC(&RC, fFinalTime);
        

  SM_D3d::SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);  
  SM_D3d::Device()->SetTexture(0, 0);    

  ClearZ(&RC, bClearColor);    

  
  SM_D3d::SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLOROP , D3DTOP_MODULATE);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  SM_D3d::SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  SM_D3d::SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
  SM_D3d::SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
  SM_D3d::SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
  SM_D3d::SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);  
  SM_D3d::SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_POINT);

  
  float fMip=-1.0f/*+2.0f+4.0f*sinf(Timer::GetTime()*0.5f)*/;
  SM_D3d::SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((DWORD*) &fMip));

  D3DMATERIAL8 Material;
  Material.Diffuse.r=Material.Diffuse.g=Material.Diffuse.b=Material.Diffuse.a=1.0f;
  Material.Ambient.r=Material.Ambient.g=Material.Ambient.b=Material.Ambient.a=1.0f;
  Material.Specular.r=Material.Specular.g=Material.Specular.b=Material.Specular.a=1.0f;
  Material.Emissive.r=Material.Emissive.g=Material.Emissive.b=Material.Emissive.a=0.0f;
  Material.Power=0.0f;
  SM_D3d::Device()->SetMaterial(&Material);


  int iIterator;
  SM_D3d::SetRenderState(D3DRS_LIGHTING, FALSE);
  MBSL_FOREACH(m_Twisters, iIterator)
  {
    SM_Twister* pDB;
    MBSL_ELEMENT(m_Twisters, iIterator, pDB);

    pDB->Render(&RC, -1, fFinalTime);;
  }
  

  unsigned i;

  if (m_bVertexColors)
  {
    SM_D3d::SetRenderState(D3DRS_COLORVERTEX, TRUE);
    SM_D3d::SetRenderState(D3DRS_LIGHTING, FALSE);
  }
  else
  {
    for (i=0 ; i<m_uLights && i<8 ; i++)
    {
      // Update light animation
      m_pLights[i].Update(fFinalTime);    

      SM_D3d::Device()->SetLight(i, m_pLights[i].GetLight());
      SM_D3d::Device()->LightEnable(i, TRUE);    
    }

    for ( ; i<8 ; i++)
    {
        SM_D3d::Device()->LightEnable(i, FALSE);
    }
    SM_D3d::SetRenderState(D3DRS_LIGHTING, m_uLights?TRUE:FALSE);
    SM_D3d::SetRenderState(D3DRS_COLORVERTEX, FALSE);  
  }
  

  SM_D3d::SetRenderState(D3DRS_AMBIENT , 0);
  SM_D3d::SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);     
  SM_D3d::SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR1);     
  SM_D3d::SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);     
  SM_D3d::SetRenderState(D3DRS_CLIPPING, TRUE);
  
  
  
  ShaderManager::SetRenderContext(&RC);

  if (m_bFog)
  {
    SM_D3d::SetRenderState(D3DRS_FOGENABLE, TRUE);  
    SM_D3d::SetRenderState(D3DRS_FOGSTART,*((int*)&m_fFogNear));
    SM_D3d::SetRenderState(D3DRS_FOGEND  ,*((int*)&m_fFogFar));
    SM_D3d::SetRenderState(D3DRS_FOGCOLOR,m_uColor);
    SM_D3d::SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);
  }
  
  if (!m_bRenderShadows)
  {
    unsigned j;
    for (j=0 ; j<1 ; j++)
    {
      for (i=0 ; i<m_uMeshes ; i++)
      {
        if (!m_pMeshes[i].m_pParent
             && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
        {
          m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, false, true, true, false,  0);            
        }
      }  
    }
  }
  else
  {
    // Render first objects that dont receive shadows with full lighting information
    unsigned j;
    
    for (i=0 ; i<m_uMeshes ; i++)
    {
      if (!m_pMeshes[i].m_pParent
           && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
      {
        m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, false, false, true, false, 0);            
      }
    } 
    RenderPipeline::Flush();
    

    // Setup ambient light
    float ar = 0.0f, ag = 0.0f, ab =0.0f;

    for (i=0 ; i<m_uLights && i<8 ; i++)
    {
      ar += m_pLights[i].GetLight()->Ambient.r;
      ag += m_pLights[i].GetLight()->Ambient.g;
      ab += m_pLights[i].GetLight()->Ambient.b;

      SM_D3d::Device()->LightEnable(i, FALSE);              
    }
    

    SM_D3d::Device()->LightEnable(0, TRUE);              
    D3DLIGHT8 AmbientLight;

    AmbientLight.Type    = D3DLIGHT_DIRECTIONAL;
    AmbientLight.Diffuse.a = 0.0f; AmbientLight.Diffuse.r = 0.0f; AmbientLight.Diffuse.g = 0.0f; AmbientLight.Diffuse.b = 0.0f;
    AmbientLight.Ambient.a = 0.0f; AmbientLight.Ambient.r = ar; AmbientLight.Ambient.g = ag; AmbientLight.Ambient.b = ab;
    AmbientLight.Specular.a= 0.0f; AmbientLight.Specular.r= 0.0f; AmbientLight.Specular.g= 0.0f;  AmbientLight.Specular.b= 0.0f; 
    AmbientLight.Direction.x = 1.0f; AmbientLight.Direction.y = 0.0f; AmbientLight.Direction.z = 0.0f;
    AmbientLight.Attenuation0 = 1.0f; AmbientLight.Attenuation1 = 0.0f; AmbientLight.Attenuation2 = 0.0f;
    AmbientLight.Range = 0.0f;
    AmbientLight.Falloff = 1.0f;
    
    SM_D3d::Device()->SetLight(0, &AmbientLight);
      
    // Render with ambient light updating z
    for (i=0 ; i<m_uMeshes ; i++)
    {
      if (!m_pMeshes[i].m_pParent
           && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
      {
        m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, false, true, false, false, 0);            
      }
    }  
    
    
    RenderPipeline::Flush();

    for (j=0 ; j<m_uLights ; j++)
    {
      D3DLIGHT8 NormalLight = *m_pLights[j].GetLight();
      NormalLight.Ambient.a = NormalLight.Ambient.r = NormalLight.Ambient.g = NormalLight.Ambient.b = 0.0f;
      SM_D3d::Device()->SetLight(0, &NormalLight);
      SM_D3d::Device()->Clear(0, 0, D3DCLEAR_STENCIL, 0x00000000, 1.0f, 0);

      SM_D3d::SetRenderState(D3DRS_STENCILENABLE, TRUE);                 
      SM_D3d::SetRenderState(D3DRS_LIGHTING, FALSE);  
      SM_D3d::SetRenderState(D3DRS_COLORWRITEENABLE, 0x0);

      
      for (i=0 ; i<m_uMeshes ; i++)
      {
        if (!m_pMeshes[i].m_pParent
             && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
        {
          m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, true, false, false, false, &m_pLights[j]);            
        }
      } 
      
      SM_D3d::SetRenderState(D3DRS_COLORWRITEENABLE, 0xF);
      
      SM_D3d::SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
      SM_D3d::SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
      SM_D3d::SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
      SM_D3d::SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
      SM_D3d::SetRenderState(D3DRS_STENCILREF, 0);
      SM_D3d::SetRenderState(D3DRS_LIGHTING, TRUE);  

      ShaderManager::OverrideBlend(true);      
      for (i=0 ; i<m_uMeshes ; i++)
      {
        if (!m_pMeshes[i].m_pParent
             && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
        {
          m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, false, true, false, false, 0);            
        }
      }
      RenderPipeline::Flush();
      ShaderManager::OverrideBlend(false);
      
      
      SM_D3d::SetRenderState(D3DRS_STENCILENABLE, FALSE);           
    }    
  }
  

  RenderPipeline::Flush();

  SM_Metaballs::ClearMetaballs();
  MBSL_FOREACH(m_Metaballs, iIterator)
  {
    D3DMesh* pMesh;
    MBSL_ELEMENT(m_Metaballs, iIterator, pMesh);
    
    Metaball b;   
    pMesh->GetKeyFrame(fFinalTime, &b.m_v3dPosition, 0);
    SM_Metaballs::AddMetaball(&b);    
  }

  MBSL_FOREACH(m_Metaballs, iIterator)
  {
    D3DMesh* pMesh;
    MBSL_ELEMENT(m_Metaballs, iIterator, pMesh);
    SM_Metaballs::SetShader(pMesh->GetGeometry()->m_pMeshElements[0].m_iShader);
    break;    
  }

  SM_Metaballs::Render(&RC, -1);
  RenderPipeline::Flush();


  MBSL_FOREACH(m_GeomMorphers, iIterator)
  {
    SM_GeomMorpher* pGM;
    MBSL_ELEMENT(m_GeomMorphers, iIterator, pGM);

    pGM->Render(&RC, -1, fFinalTime);
    RenderPipeline::Flush();
  }  

  MBSL_FOREACH(m_DistortBalls, iIterator)
  {
    SM_DistortBall* pDB;
    MBSL_ELEMENT(m_DistortBalls, iIterator, pDB);

    pDB->Render(&RC, -1, fFinalTime);
    RenderPipeline::Flush();
  }  

  MBSL_FOREACH(m_SpikeTubes, iIterator)
  {
    SM_SpikeTube* pDB;
    MBSL_ELEMENT(m_SpikeTubes, iIterator, pDB);

    pDB->Render(&RC, -1, fFinalTime);
    RenderPipeline::Flush();
  }    

  MBSL_FOREACH(m_FFTBalls, iIterator)
  {
    SM_FFTBall* pGM;
    MBSL_ELEMENT(m_FFTBalls, iIterator, pGM);

    pGM->Render(&RC, -1, fFinalTime);
    RenderPipeline::Flush();
  }  

  
  RenderPipeline::Flush();

  // Particle systems   
  SM_D3d::SetRenderState(D3DRS_SPECULARENABLE , FALSE);
  SM_D3d::SetRenderState(D3DRS_LOCALVIEWER , FALSE);
  SM_D3d::SetRenderState(D3DRS_LIGHTING, FALSE);  
  SM_D3d::SetRenderState(D3DRS_FOGENABLE, FALSE);  
  

  RenderPipeline::Flush();

  MBSL_FOREACH(m_ParticleSystems, iIterator)
  {
    RenderParticleSystem* pPS;
    MBSL_ELEMENT(m_ParticleSystems, iIterator, pPS);

    pPS->Render(&RC, -1, fFinalTime);
  }
  RenderPipeline::Flush();
  
  
  unsigned j;
  for (j=0 ; j<1 ; j++)
  {
    for (i=0 ; i<m_uMeshes ; i++)
    {
      if (!m_pMeshes[i].m_pParent
           && m_pMeshes[i].GetGeometry()->m_pcName[0] != '@')
      {
        m_pMeshes[i].Render(&RC, iOutcode, fFinalTime, false, false, false, true, 0);            
      }
    } 
  }

 
    
  

  SM_D3d::Device()->SetVertexShader(FVF_POSNORMALDIFFUSETEX1);                            

  RenderPipeline::Flush();  
}

void MaxScene::RenderShadows()
{
  
}

Vector3D* MaxScene::GetVector3D   (MetaFileNode* pNode, Vector3D* pVector3D)
{
  assert(pNode->m_Sons[0]->m_Token.m_eType==MetaFileToken::E_FLOAT);
  assert(pNode->m_Sons[1]->m_Token.m_eType==MetaFileToken::E_FLOAT);
  assert(pNode->m_Sons[2]->m_Token.m_eType==MetaFileToken::E_FLOAT);

  pVector3D->x=pNode->m_Sons[0]->m_Token.m_fValue;
  pVector3D->y=pNode->m_Sons[1]->m_Token.m_fValue;
  pVector3D->z=pNode->m_Sons[2]->m_Token.m_fValue;
  return (pVector3D);
}

int* MaxScene::GetInt(MetaFileNode* pNode, int* pInt)
{
  assert(pNode->m_Sons[0]->m_Token.m_eType==MetaFileToken::E_INT);

  *pInt=pNode->m_Sons[0]->m_Token.m_iValue;
  return (pInt);
}

const char*       GetString(MetaFileNode* pNode)
{
  assert(pNode->m_Sons[0]->m_Token.m_eType==MetaFileToken::E_STRING);

  return (pNode->m_Sons[0]->m_Token.m_pszString);
}
  


float* MaxScene::GetFloat(MetaFileNode* pNode, float* pFloat)
{
  assert(pNode->m_Sons[0]->m_Token.m_eType==MetaFileToken::E_FLOAT);

  *pFloat=pNode->m_Sons[0]->m_Token.m_fValue;
  return (pFloat);
}

Quaternion* MaxScene::GetQuaternion (MetaFileNode* pNode, Quaternion* pQuaternion)
{
  assert(pNode->m_Sons[0]->m_Token.m_eType==MetaFileToken::E_FLOAT);
  assert(pNode->m_Sons[1]->m_Token.m_eType==MetaFileToken::E_FLOAT);
  assert(pNode->m_Sons[2]->m_Token.m_eType==MetaFileToken::E_FLOAT);
  assert(pNode->m_Sons[3]->m_Token.m_eType==MetaFileToken::E_FLOAT);

  pQuaternion->x=pNode->m_Sons[0]->m_Token.m_fValue;
  pQuaternion->y=pNode->m_Sons[1]->m_Token.m_fValue;
  pQuaternion->z=pNode->m_Sons[2]->m_Token.m_fValue;
  pQuaternion->w=pNode->m_Sons[3]->m_Token.m_fValue;
  return (pQuaternion);
}


ScalarSequence* MaxScene::GetScalarSequence(MetaFileNode* pNode, ScalarSequence* pScalarSequence)
{
  std::vector<float> floats;

  unsigned i;

  for (i=0 ; i<pNode->m_Sons.size() ; i++)
  {
    floats.push_back(pNode->m_Sons[i+0]->m_Token.m_fValue);
  }

  pScalarSequence->m_uScalars=floats.size();
  pScalarSequence->m_pScalars=new float[pScalarSequence->m_uScalars];
  if (!pScalarSequence->m_pScalars)
  {
    return (0);
  }

  for (i=0 ; i<pScalarSequence->m_uScalars ; i++)
  {
    pScalarSequence->m_pScalars[i]=floats[i];
  }

  
  pScalarSequence->m_uSamplingRate=iFPS;

  return (pScalarSequence);
}

KeyFrameSequence* MaxScene::GetKeyFrameSequence(MetaFileNode* pNode, KeyFrameSequence* pKeyFrameSequence)
{
  KeyFrame k;

  std::vector<KeyFrame> KeyFrames;

  unsigned i;

  for (i=0 ; i<pNode->m_Sons.size() ; i+=7)
  {
    k.m_Position.x=pNode->m_Sons[i+0]->m_Token.m_fValue;
    k.m_Position.y=pNode->m_Sons[i+1]->m_Token.m_fValue;
    k.m_Position.z=pNode->m_Sons[i+2]->m_Token.m_fValue;

    k.m_Rotation.x=pNode->m_Sons[i+3]->m_Token.m_fValue;
    k.m_Rotation.y=pNode->m_Sons[i+4]->m_Token.m_fValue;
    k.m_Rotation.z=pNode->m_Sons[i+5]->m_Token.m_fValue;
    k.m_Rotation.w=pNode->m_Sons[i+6]->m_Token.m_fValue;

    KeyFrames.push_back(k);
  }

  pKeyFrameSequence->m_uKeyFrames=KeyFrames.size();
  pKeyFrameSequence->m_pKeyFrames=new KeyFrame[pKeyFrameSequence->m_uKeyFrames];
  if (!pKeyFrameSequence->m_pKeyFrames)
  {
    return (0);
  }

  for (i=0 ; i<pKeyFrameSequence->m_uKeyFrames ; i++)
  {
    pKeyFrameSequence->m_pKeyFrames[i]=KeyFrames[i];
  }

  for (i=0 ; i<pKeyFrameSequence->m_uKeyFrames-1 ; i++)
  {
    if (pKeyFrameSequence->m_pKeyFrames[i].m_Rotation.Dot(pKeyFrameSequence->m_pKeyFrames[i+1].m_Rotation)<0)
    {
      pKeyFrameSequence->m_pKeyFrames[i+1].m_Rotation=-pKeyFrameSequence->m_pKeyFrames[i+1].m_Rotation;
    }
  }

  pKeyFrameSequence->m_fSamplingRate=(float) iFPS;

  return (pKeyFrameSequence);
}

int MaxScene::LoadBin(MVFSFILE* f)
{
  unsigned    i;
  RenderMesh  RenderMesh;
  

  Shutdown();
  Init();

  // Version
  int iVersion;
  if (MVFS::fread(&iVersion, sizeof(MAXSCENE_FILEVER), 1, f)!=1) return -1;

  iActualFileVer=iVersion;

  if (iVersion!=MAXSCENE_FILEVER)
  {
    SM_Main::OutputError("El .3px es de una version antigua. Borra todos los .3px y reexportalos por favor\n");
    goto HADERROR;
  }


  // Load meshes  
  if (MVFS::fread(&m_uMeshes, sizeof(m_uMeshes), 1, f)!=1) return -1;

  m_pMeshes=new D3DMesh[m_uMeshes];
  if (!m_pMeshes)
  {
    goto HADERROR;
  }

  
  // Generate Render Meshes
  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (!RenderMesh.Load(f))
    {
      goto HADERROR;
    }
 
    D3DGeometry* pGeometry=new D3DGeometry;
    if (!pGeometry)
    {
      goto HADERROR;
    }

    if (pGeometry->Init(&RenderMesh))
    {
      goto HADERROR;
    }

    if (m_pMeshes[i].Init()!=0)
    {
      goto HADERROR;
    }

    if (pGeometry->GenerateShadowVolume() != 0)
    {
      goto HADERROR;
    }
    
    // Assign Geometry
    m_pMeshes[i].SetGeometry(pGeometry);


    // Position
    KeyFrame k;
    if (MVFS::fread(&k, sizeof(KeyFrame), 1, f)!=1)
    {
      goto HADERROR;
    }

    m_pMeshes[i].SetPosition(&k.m_Position);
    m_pMeshes[i].SetRotation(&k.m_Rotation);


    // Pivot
    if (MVFS::fread(&k, sizeof(KeyFrame), 1, f)!=1)
    {
      goto HADERROR;
    }

    m_pMeshes[i].SetPivotPosition(&k.m_Position);
    m_pMeshes[i].SetPivotRotation(&k.m_Rotation);


    if (MVFS::fread(&m_pMeshes[i].m_pParent, sizeof(int), 1, f)!=1)
    {
      goto HADERROR;
    }
  }

  // Construct hierarchy
  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (int(m_pMeshes[i].m_pParent)==-1)
    {
      m_pMeshes[i].m_pParent=0;
    }
    else
    {
      m_pMeshes[i].m_pParent=m_pMeshes+int(m_pMeshes[i].m_pParent);
      m_pMeshes[i].m_pParent->AddSon(&m_pMeshes[i]);
    }
  }

  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (m_pMeshes[i].m_pD3DGeometry->m_pcName[0]=='*')
    {
      m_pMeshes[i].m_bVisible=false;
    }
  }
    
  if (MVFS::fread(&m_uLights, sizeof(m_uLights), 1, f)!=1)
  {
    goto HADERROR;
  }

  m_pLights=new D3DLight[m_uLights];
  if (!m_pLights)
  {
    goto HADERROR;
  }

  for (i=0 ; i<m_uLights ; i++)
  {
    if (m_pLights[i].Load(f)!=0)
    {
      goto HADERROR;
    }
  }

  // Cameras
  if (MVFS::fread(&m_uCameras, sizeof(m_uCameras), 1, f)!=1) 
  {
    goto HADERROR;
  }


  m_pCameras=new MaxCamera[m_uCameras];
  if (!m_pCameras)
  {
    goto HADERROR;
  }

  for (i=0 ; i<m_uCameras ; i++)
  {
    if (m_pCameras[i].Load(f)!=0)
    {
      goto HADERROR;
    }
  }

  // Keyframes
  if (MVFS::fread(&m_uKeyFrames, sizeof(m_uKeyFrames), 1, f)!=1) return -1;

  m_pKeyFrames=new KeyFrameSequence[m_uKeyFrames];
  if (!m_pKeyFrames)
  {
    goto HADERROR;
  }

  for (i=0 ; i<m_uKeyFrames ; i++)
  {
    if (m_pKeyFrames[i].Load(f)!=0)
    {
      goto HADERROR;
    }
  }

  for (i=0 ; i<m_uKeyFrames ; i++)
  {
    int iType, iIndex=-1;
  
    if (MVFS::fread(&iType , sizeof(int), 1, f)!=1) return -1;
    if (MVFS::fread(&iIndex, sizeof(int), 1, f)!=1) return -1;

    if (iIndex==-1)
    {
      continue;
    }

    switch (iType)
    {
    case E_MESH:
      m_pMeshes[iIndex].SetKeyFrameSequence(&(m_pKeyFrames[i]));
      break;
    case E_CAMERA:
      m_pCameras[iIndex].SetKeyFrameSequence(&(m_pKeyFrames[i]));
      break;
    case E_LIGHT:
      m_pLights[iIndex].SetKeyFrameSequence(&(m_pKeyFrames[i]));
      break;
    }    
  }

  if (iVersion>=2)
  {
    // Keyframes
    if (MVFS::fread(&m_uScalars, sizeof(m_uScalars), 1, f)!=1) return -1;

    m_pScalars=new ScalarSequence[m_uScalars];
    if (!m_pScalars)
    {
      goto HADERROR;
    }

    for (i=0 ; i<m_uScalars; i++)
    {
      if (m_pScalars[i].Load(f)!=0)
      {
        goto HADERROR;
      }
    }
    
    for (i=0 ; i<m_uScalars ; i++)
    {      
      int iType, iIndex=-1;
  
      if (MVFS::fread(&iType , sizeof(int), 1, f)!=1) return -1;
      if (MVFS::fread(&iIndex, sizeof(int), 1, f)!=1) return -1;

      if (iIndex==-1)
      {
        continue;
      }

      switch (iType)
      {
      case E_CAMERA:
        m_pCameras[iIndex].SetScalarSequence(&(m_pScalars[i]));
        break;
      }    
    }
  }

  
  // Create special stuff
  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (m_pMeshes[i].GetGeometry()->m_pcName[0] == '@')
    {
      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "PARTICLE", strlen("PARTICLE")) == 0)
      {
        RenderParticleSystem* pParticleSystem = new RenderParticleSystem;
        if (pParticleSystem)
        {
          pParticleSystem->m_v3dPosition = m_pMeshes[i].m_Position;
          pParticleSystem->m_qRotation   = m_pMeshes[i].m_Quaternion;          
          pParticleSystem->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_ParticleSystems.InsertTail(pParticleSystem);
        }
      }

      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "SPHERICAL", strlen("SPHERICAL")) == 0)
      {
        SM_GeomMorpher* pGeomMorpher = new SM_GeomMorpher;
        if (pGeomMorpher)
        {
          pGeomMorpher->m_v3dPosition = m_pMeshes[i].m_Position;
          pGeomMorpher->m_qRotation   = m_pMeshes[i].m_Quaternion;     
          pGeomMorpher->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_GeomMorphers.InsertTail(pGeomMorpher);
        }
      }
      
      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "BOLASYNC", strlen("BOLASYNC")) == 0)
      {
        SM_FFTBall* pFFTBall = new SM_FFTBall;
        if (pFFTBall)
        {
          pFFTBall->m_v3dPosition = m_pMeshes[i].m_Position;
          pFFTBall->m_qRotation   = m_pMeshes[i].m_Quaternion;     
          pFFTBall->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_FFTBalls.InsertTail(pFFTBall);
        }
      }
      

      


      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "METABALL", strlen("METABALL")) == 0)
      {
        m_Metaballs.InsertTail(&m_pMeshes[i]);        
      }      

      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "DISTORTBALL", strlen("DISTORTBALL")) == 0)
      {
        SM_DistortBall* pDistBall = new SM_DistortBall;
        if (pDistBall)
        {
          pDistBall->m_v3dPosition = m_pMeshes[i].m_Position;
          pDistBall->m_qRotation   = m_pMeshes[i].m_Quaternion;     
          pDistBall->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_DistortBalls.InsertTail(pDistBall);
        }
      }

      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "SPIKETUBE", strlen("SPIKETUBE")) == 0)
      {
        SM_SpikeTube* pSpikeTube = new SM_SpikeTube;
        if (pSpikeTube)
        {
          pSpikeTube->m_v3dPosition = m_pMeshes[i].m_Position;
          pSpikeTube->m_qRotation   = m_pMeshes[i].m_Quaternion;     
          pSpikeTube->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_SpikeTubes.InsertTail(pSpikeTube);
        }
      }

      if (strncmp(m_pMeshes[i].GetGeometry()->m_pcName+1, "TRAUMA", strlen("TRAUMA")) == 0)
      {
        SM_Twister* pTwister= new SM_Twister;
        if (pTwister)
        {
          pTwister->m_v3dPosition = m_pMeshes[i].m_Position;
          pTwister->m_qRotation   = m_pMeshes[i].m_Quaternion;     
          pTwister->Init(m_pMeshes[i].GetGeometry()->m_pMeshElements[0].m_iShader, &m_pMeshes[i]);
          m_Twisters.InsertTail(pTwister);
        }
      }
    }    
  }

  
  iActualFileVer=-1;
  return 0;

HADERROR:
  iActualFileVer=-1;
  return -1;
}



D3DGeometry* MaxScene::GetGeometry(char* pcName)
{
  
  unsigned i;
  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (strcmp(m_pMeshes[i].GetGeometry()->m_pcName, pcName)==0)
    {
      return m_pMeshes[i].GetGeometry();
    }
  }
  

  return 0;
}

D3DMesh* MaxScene::GetMesh(char* pcName)
{
  
  unsigned i;
  for (i=0 ; i<m_uMeshes ; i++)
  {
    if (strcmp(m_pMeshes[i].GetGeometry()->m_pcName, pcName)==0)
    {
      return &m_pMeshes[i];
    }
  }
  

  return 0;
}

void MaxScene::SetParticleSystemParams(const char* pcName, const char* pcParams)
{
  int iIterator;
  MBSL_FOREACH(m_ParticleSystems, iIterator)
  {
    RenderParticleSystem* pPS;
    MBSL_ELEMENT(m_ParticleSystems, iIterator, pPS);

    if (strcmp(pPS->GetMesh()->m_pD3DGeometry->m_pcName, pcName) == 0)
    {
      pPS->SetParams(pcParams);
    }
  }
}
