#include "SM_DemoScriptPCH.h"
#include "SM_DemoScript.h"
#include "SM_DemoEffect.h"
#include "SM_DemoTune.h"
#include "SM_Main.h"
#include "SM_Music.h"

namespace Timer
{
  extern float SetTime(float fTime);
  extern float GetTime();
}


//#define USEDDRAW
#ifdef USEDDRAW
#include "SM_Ddraw.h"
#endif

#include "SM_Keyboard.h"
#include "SM_Conversiones.h"

#define USE_MMX

float                       g_fWaitTime=0.0f;
float                       g_fMP3Time=-1.0f;
bool                        g_bRunToMode = false;
float                       g_fLastSync = 0.0f;
int                         g_iPos=-1;
int                         g_iRow=-1;
bool                        g_bActive = true;



namespace SM_DemoScript
{

TCommandNode*	              m_pCommandList;
TCommandNode*	              m_pCommandListLastNode;



SM_DEData::CVideoBuffer			g_sLocalVideo;
bool							          g_bLocalVideo=true;
bool							          g_bForcedHardConversion=false;
								            
bool							          g_bWaitingSync=false;
bool							          g_bVideoInit=false;
								            
bool							          g_bClearScreen=false;
SM_DemoTune*                g_pPlayingTune=0;
								            

bool							          g_bVideoRestore=false;

bool                        g_bMP3Play=false;

bool                        g_bIgnoreLoads=false;

								            
float							          g_fStartTime;
//float                       g_fTime;
float							          g_fDeactivateTime;

bool                        m_bLooped;  

int StopMusic();
int PlayMusic(SM_DemoTune* pTune, bool bLooped);
int SkipMusicTime(float fTime);
int SkipMusicPosRow(int iPos, int iRow);


class NotifyHandler : public SM_Main::INotifier
{
  void OnActivate(bool bActive)
  {
    g_bActive=bActive;
    if (bActive)
    {
      g_fStartTime+=GetTime()-g_fDeactivateTime;      
      if (g_bMP3Play)
      {
        if (g_pPlayingTune) SM_Music::MP3Play();     
      }
      else
      {
        if (g_pPlayingTune) SM_Music::Play();     
      }
      SM_Main::OutputConsole("PLAY\n");
    }
    else
    {
      g_fDeactivateTime=GetTime();      
      if (g_pPlayingTune) SM_Music::Pause();     
      SM_Main::OutputConsole("PAUSE\n");
    }
  }

  void OnDisplayChange()
  {
    g_bVideoRestore=true;
  }
};


NotifyHandler     Notify;


struct SM_DemoEffectNode
{
	SM_DemoEffect*     pEffect;
	SM_DemoEffectNode* pNext;
};


SM_DemoEffectNode*			    m_pActiveEffects;
TCommandNode*               m_pCurrentCommand;

SM_DemoTune*   GetTune(const char* pcName);


void SetLastSyncPoint(float fTime)
{
  if (g_bRunToMode)
  {
    SM_Main::OutputConsole("Setting last sync point to %f\n", fTime);
    g_fLastSync = fTime;    
  }

}

void InsertActiveFXList(SM_DemoEffect*     pEffect)
{
  SM_DemoEffectNode* pNewNode;
	pNewNode=new SM_DemoEffectNode;
	pNewNode->pEffect=pEffect;
	pNewNode->pNext   =0;

	SM_DemoEffectNode* pIterator;
	if (m_pActiveEffects)
	{
		for (pIterator=m_pActiveEffects; pIterator->pNext ;  pIterator=pIterator->pNext);        
    pIterator->pNext=pNewNode;
	}
	else
	{
		m_pActiveEffects=pNewNode;
	}
}

SM_DemoEffect*       GetFirstEffect()
{
  return 0;
}

SM_DemoEffect*       GetNextEffect()
{
  return 0;
}



SM_DemoEffectNode*			    m_pActiveEffectsIterator=0;
SM_DemoEffect*       GetFirstActiveEffect()
{
  if (m_pActiveEffects)
  {
    m_pActiveEffectsIterator=m_pActiveEffects;
    return GetNextActiveEffect();
  }

  return 0;
}

SM_DemoEffect*       GetNextActiveEffect()
{
  if (m_pActiveEffectsIterator)
  {
    SM_DemoEffect* pEffect=m_pActiveEffectsIterator->pEffect;
    m_pActiveEffectsIterator=m_pActiveEffectsIterator->pNext;
    return pEffect;
  }

  return 0;  
}


void RemoveActiveFXList(SM_DemoEffect* pEffect)
{
  SM_DemoEffectNode* pNode;
  SM_DemoEffectNode* pPrevious;

  if (!m_pActiveEffects)
    return;

  if (pEffect==m_pActiveEffects->pEffect)
  {
    SM_DemoEffectNode* pNode=m_pActiveEffects;
    m_pActiveEffects=m_pActiveEffects->pNext;
    delete pNode;    
  }
  else
  {
    for (pNode=m_pActiveEffects ; pNode ; pPrevious=pNode, pNode=pNode->pNext)
    {
      if (pEffect==pNode->pEffect)
      {
        assert(pPrevious);
        pPrevious->pNext=pNode->pNext;
        delete pNode;
        break;
      }
    }
  }
}


void ShutdownActiveFXList()
{
  // Borramos lista de efectos
  SM_DemoEffectNode* pEffectNode;
  SM_DemoEffectNode* pNextEffectNode;
  for (pEffectNode=m_pActiveEffects ;  pEffectNode ; pEffectNode=pNextEffectNode)
  {
    pNextEffectNode=pEffectNode->pNext;
	  delete pEffectNode;
  }
  m_pActiveEffects=0;
}

void InitActiveFXList()
{
  ShutdownActiveFXList();
}

void ShutdownFXList()
{  
  SM_DemoEffect* pEffect;
  for (pEffect=EffectInstances ; pEffect ; pEffect=pEffect->m_pNextEffect)
  {
    pEffect->Shutdown();
  }
}

void ResetFXList()
{  
  SM_DemoEffect* pEffect;
  for (pEffect=EffectInstances ; pEffect ; pEffect=pEffect->m_pNextEffect)
  {
    pEffect->Reset();
  }
}


int             ParseScript    (char* pcScript);
  


#ifdef USEDDRAW    
void CVideoBufferDataFromDDraw(SM_DEData::CVideoBuffer& sd, SM_DDraw::TLockData& LockData, SM_DDraw::TPixelFormat& PixelFormat)
{
  sd.m_uBPP         =PixelFormat.m_uBPP;
  sd.m_uRMask       =PixelFormat.m_uRBitMask;
  sd.m_uRShiftLeft  =PixelFormat.m_uRShiftLeft;
  sd.m_uRShiftRight =PixelFormat.m_uRShiftRight;
  sd.m_uGMask       =PixelFormat.m_uGBitMask;
  sd.m_uGShiftLeft  =PixelFormat.m_uGShiftLeft;
  sd.m_uGShiftRight =PixelFormat.m_uGShiftRight;
  sd.m_uBMask       =PixelFormat.m_uBBitMask;
  sd.m_uBShiftLeft  =PixelFormat.m_uBShiftLeft;
  sd.m_uBShiftRight =PixelFormat.m_uBShiftRight;
  sd.m_uByteStride  =LockData.m_uStride;
  sd.m_uWidth       =LockData.m_uWidth;
  sd.m_uHeight      =LockData.m_uHeight;    
}

int InitLocalVideo(SM_DDraw::TDisplay& Display)
{
  g_sLocalVideo.m_uBPP    =Display.m_uBPP;
  g_sLocalVideo.m_uWidth  =Display.m_uWidth;
  g_sLocalVideo.m_uHeight =Display.m_uHeight;
  g_sLocalVideo.m_pVideo =new char[Display.m_uWidth*Display.m_uHeight*(Display.m_uBPP>>3)];
  g_sLocalVideo.m_uByteStride=g_sLocalVideo.m_uWidth*(g_sLocalVideo.m_uBPP>>3);
  

  
  g_bLocalVideo=true;
    
  return (0);
};

int ShutdownLocalVideo()
{
  delete[] g_sLocalVideo.m_pVideo;
  memset(&g_sLocalVideo, 0, sizeof(g_sLocalVideo));

  g_bLocalVideo=false;

  return (0);
}
#endif

class MusicHandler : public SM_Music::IEventHandler
{
  virtual void  Notify(int iPos, int iRow)
  {
    g_iPos=iPos;
    g_iRow=iRow;
  }
};

MusicHandler      Music;



TCommand::TCommand()
{
  Init();
}

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

int TCommand::Init()
{
  m_Command   =CM_ERROR;
  m_pEffect   =0;
  m_pcArgs    =0;
  m_iRow      =-1;
  m_iPos      =-1;    
  
  return (0);
}

int TCommand::Shutdown()
{
  if (m_pcArgs)   { delete[] m_pcArgs; m_pcArgs = 0;}
  Init();

  return (0);
}

void TCommand::SetCommand(eCommand  Command)
{
  m_Command=Command;
}

TCommand::eCommand TCommand::GetCommand()
{
  return m_Command;
}

void TCommand::SetFx(SM_DemoEffect*  pEffect)
{
  m_pEffect = pEffect;
}

void TCommand::SetTune(SM_DemoTune*  pTune)
{
  m_pTune = pTune;
}

const char*  TCommand::GetTuneName()
{
  return m_pTune->m_pcInstanceName;
}

const char*  TCommand::GetFxName()
{
  return (m_pEffect->m_pcInstanceName);
}

SM_DemoEffect*  TCommand::GetFx()
{
  return m_pEffect;
}

void  TCommand::SetTime(float fTime)
{
  m_fTime=fTime;
}

float TCommand::GetTime()
{
  return (m_fTime);
}

void TCommand::SetLoop(bool bLoop)
{
  m_bLoop=bLoop;
}

bool TCommand::GetLoop()
{
  return m_bLoop;
}



void TCommand::SetArgs(const char*  pcArgs)
{
  if (m_pcArgs) delete[] m_pcArgs;

  m_pcArgs=new char[strlen(pcArgs)+1];
  strcpy(m_pcArgs, pcArgs);
}

char* TCommand::GetArgs()
{
  return (m_pcArgs);
}

void TCommand::SetPosRow(int iPos , int iRow)
{
  m_iPos=iPos;
  m_iRow=iRow;
}

void TCommand::GetPosRow(int& iPos, int& iRow)
{
  iPos=m_iPos;
  iRow=m_iRow;
}

void TCommand::SetVideo(unsigned uResX, unsigned uResY, unsigned uBPP, bool bFullscreen)
{
  m_uResX       =uResX;
  m_uResY       =uResY;
  m_uBPP        =uBPP;
  m_bFullscreen =bFullscreen;
}

void TCommand::GetVideo(unsigned& uResX, unsigned& uResY, unsigned& uBPP, bool& bFullscreen)
{
  uResX      =m_uResX;
  uResY      =m_uResY;
  uBPP       =m_uBPP;
  bFullscreen=m_bFullscreen;
}

TCommand* TCommand::Clone()
{
  TCommand* pClone = new TCommand();
  if (!pClone)
  {
    return 0;
  }

  memcpy(pClone, this, sizeof(TCommand));

  if (pClone->m_pcArgs)
  {
    pClone->m_pcArgs = new char[strlen(pClone->m_pcArgs)+1];
    if (!pClone->m_pcArgs)
    {
      goto FAIL;
    }
    strcpy(pClone->m_pcArgs, m_pcArgs);
  }
  
  
  return pClone;

FAIL:
  delete pClone;
  return 0;
}

int TCommand::ToString(char* pcString, unsigned uLen)
{
  uLen--;

  int iReturn = -1;
  switch (m_Command)
  {
    case CM_FX_START: 
      iReturn = _snprintf(pcString, uLen, "FXSTART %s\n", GetFxName());
      break;
    case CM_FX_STOP: 
      iReturn = _snprintf(pcString, uLen, "FXSTOP %s\n", GetFxName());
      break;
    case CM_FX_LOAD: 
      iReturn = _snprintf(pcString, uLen, "FXLOAD %s %s\n", GetFxName(), GetArgs());
      break;
    case CM_FX_SHUT: 
      iReturn = _snprintf(pcString, uLen, "FXSHUT %s\n", GetFxName());
      break;
    case CM_FX_COMMAND: 
      iReturn = _snprintf(pcString, uLen, "FXCOMMAND %s %s\n", GetFxName(), GetArgs());
      break;
    case CM_SYS_SYNC: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_VIDEOSTART: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_VIDEOEND: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_LOADMP3: 
      iReturn = _snprintf(pcString, uLen, "LOADMP3 %s %s\n", GetTuneName(), GetArgs());
      break;
    case CM_SYS_LOADTRACK: 
      iReturn = _snprintf(pcString, uLen, "LOADTRACK %s %s\n", GetTuneName(), GetArgs());
      break;
    case CM_SYS_FREEMUSIC: 
      iReturn = _snprintf(pcString, uLen, "FREEMUSIC %s\n", GetTuneName());
      break;
    case CM_SYS_PLAYMUSIC: 
      iReturn = _snprintf(pcString, uLen, "PLAYMUSIC %s %s\n", GetTuneName(), GetLoop()?"LOOP":"NOLOOP");
      break;
    case CM_SYS_STOPMUSIC: 
      iReturn = _snprintf(pcString, uLen, "STOPMUSIC %s\n", GetTuneName());
      break;
    case CM_SYS_SKIPTO: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_SKIPTOTIME: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_SYNCTIME: 
      iReturn = _snprintf(pcString, uLen, "SYNCTIME %f\n", GetTime());
      break;
    case CM_SYS_CLEARON: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_CLEAROFF: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_MEMBACKBUFFER: 
      assert(!"UNSUPPORTED");
      break;
    case CM_SYS_VIDEOBACKBUFFER: 
      assert(!"UNSUPPORTED");
      break; 
    case CM_SYS_DUMP: 
      iReturn = _snprintf(pcString, uLen, "DUMP\n");
      break;
    case CM_SYS_WAIT: 
      iReturn = _snprintf(pcString, uLen, "WAIT %f\n", GetTime());
      break;
    default:
      assert(!"Unexpected command");      
  }

  pcString[uLen-1] = '\0';

  return iReturn;
}

int Init(char* pcScript, bool bLooped, bool bIgnoreLoads)
{
  g_bIgnoreLoads = bIgnoreLoads;
  m_bLooped=bLooped;
  m_pCurrentCommand =0;
  m_pCommandList    =0;  
  m_pActiveEffects  =0;
  g_bRunToMode = false;
  g_fLastSync = 0.0f;


  #ifdef USEDDRAW
  if (SM_DDraw::Init()!=0)
  {
    MessageBox(NULL, "Couldn't start video sys. Quitting", "Error", MB_OK);
    return (-1);
  }
  #endif
  
  SM_Main::SetNotifyHandler(&Notify);

  // Enumeramos efectos
  EnumerateFx();


  SM_DemoEffect* pEffect;

  SM_Main::OutputConsole("Enumerating effects...\n");
  for (pEffect=EffectInstances ; pEffect ; pEffect=pEffect->m_pNextEffect)
  {
    SM_Main::OutputConsole("%s\n", pEffect->m_pcInstanceName);
  }
  SM_Main::OutputConsole("Enumerating ended...\n");

  m_pCommandList    =0;  
  m_pActiveEffects  =0;

  if (ParseScript(pcScript))
  {
    SM_Main::OutputError("%s\n", "Error parsing script. Quitting");
    return (-1);
  }

  g_fStartTime=GetTime();
 
  return (0);
}

int Shutdown()
{
  // Borramos lista de comandos  
  ShutdownCommandList();

  // efectos activos
  ShutdownActiveFXList();

  // Borramos lista de efectos
  ShutdownFXList();

  #ifdef USEDDRAW
  if (g_bLocalVideo)
  {
    ShutdownLocalVideo();
  }
  #endif

  
  SM_Main::SetNotifyHandler(0);

  #ifdef USEDDRAW
  SM_DDraw::Shutdown();     
  #endif

  return (0);
}

int Reset()
{
  // shutdown actives
  ShutdownActiveFXList();

  // reset all effects
  ResetFXList();


  m_pCurrentCommand=m_pCommandList;
  g_bRunToMode = false;
  g_fLastSync = 0.0f;
  
  return 0;
}

unsigned uPosition;
unsigned uMax;
char*    pcTokenBuffer;                           
unsigned uBracketCount=0;

char* GetToken(bool bUntilEndLine=false)
{
  char* pcToken;

START:
  while (pcTokenBuffer[uPosition]=='\r' ||
         pcTokenBuffer[uPosition]=='\t' ||
         pcTokenBuffer[uPosition]==' '  ||
         (bUntilEndLine?0:pcTokenBuffer[uPosition]=='\n'))
  {
    uPosition++;
  }

  if (uPosition==uMax)
  {
    return (NULL);
  }

  // Chequeamos si es comentario
  if (pcTokenBuffer[uPosition  ]=='/' &&
      pcTokenBuffer[uPosition+1]=='/')
  {
    // Vamos hasta final de linea
    while (pcTokenBuffer[uPosition]!='\n' && uPosition<uMax)
    {
      uPosition++;
    }
      
    goto START;
  }

  if (pcTokenBuffer[uPosition]=='[')
  {
    uBracketCount++;
    uPosition++;
    while (uBracketCount && uPosition<uMax)
    {
      if (pcTokenBuffer[uPosition]=='[') uBracketCount++;
      if (pcTokenBuffer[uPosition]==']') uBracketCount--;   
      uPosition++;
    }

    uBracketCount=0;
    goto START;
  }

  pcToken=&(pcTokenBuffer[uPosition]);

  // Avanzamos hasta encontrar un separador  
  while ( (bUntilEndLine?
            1:
            pcTokenBuffer[uPosition]!='\t'       &&
            pcTokenBuffer[uPosition]!=' '    )   &&
            pcTokenBuffer[uPosition]!='\r'       &&
            pcTokenBuffer[uPosition]!='\n'       &&
            uPosition!=uMax)
  {
    uPosition++;    
  }
  

  pcTokenBuffer[uPosition]='\0';
  if (uPosition!=uMax)
  {
    uPosition++;
  }

  _strupr(pcToken);
  return (pcToken);
}

#define CONDITIONALERROR(x, error, caption)  {if (!x) { SM_Main::OutputError("%s : %s", error, caption); return (-1);}}

int ParseScript(char* pcScript)
{


  pcTokenBuffer=pcScript;
  uPosition    =0;
  uMax         =strlen(pcScript);
  
  char* pcToken;
  while (pcToken=GetToken()) 
  {
	TCommand* pCommand=0;

    if (strcmp(pcToken, "FXLOAD")==0)
    {
      pcToken=GetToken();
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_LOAD);
      pCommand->SetFx(GetEffect(pcToken));      
      pcToken=GetToken(true);
      pCommand->SetArgs(pcToken);      
    }
    else
    if (strcmp(pcToken, "FXSHUT")==0)
    {     
      pcToken=GetToken();     
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_SHUT);
      pCommand->SetFx(GetEffect(pcToken));
    }
    else
    if (strcmp(pcToken, "FXSTOP")==0)
    {
      pcToken=GetToken();     
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_STOP);
      pCommand->SetFx(GetEffect(pcToken));
    }
    else
    if (strcmp(pcToken, "FXSTART")==0)
    {
      pcToken=GetToken();     
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_START);
      pCommand->SetFx(GetEffect(pcToken));
    }
    else
    if (strcmp(pcToken, "FXCOMMAND")==0)
    {      
      pcToken=GetToken();     
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_COMMAND);
      pCommand->SetFx(GetEffect(pcToken));
      pcToken=GetToken(true);
      pCommand->SetArgs(pcToken);      
    }
    else
    if (strcmp(pcToken, "FXLAYER")==0)
    {      
      pcToken=GetToken();     
      CONDITIONALERROR(GetEffect(pcToken), pcToken, "Referenced effect doesn't exist");      
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_FX_LAYER);
      pCommand->SetFx(GetEffect(pcToken));
      pcToken=GetToken(true);
      pCommand->SetArgs(pcToken);      
    }
    else
    if (strcmp(pcToken, "SYNC")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_SYNC);
      pcToken=GetToken();
      int iPos=atoi(pcToken);
      pcToken=GetToken();
      int iRow=atoi(pcToken);
      pCommand->SetPosRow(iPos, iRow);      
    }
    else
    if (strcmp(pcToken, "LOADMUSIC")==0)
    { 
      assert(!"Not compatible any more");
      /*
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_LOADMUSIC);
      pcToken=GetToken();
      pCommand->SetArgs(pcToken);              
      */
    }
    else
    if (strcmp(pcToken, "STOPMUSIC")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_STOPMUSIC);      
    }
    else if (strcmp(pcToken, "VIDEOSTART")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");

      pcToken=GetToken(true);
      unsigned uResX, uResY, uBPP, uFullscreen;
      if (sscanf(pcToken, "%u%u%u%u", &uResX, &uResY, &uBPP, &uFullscreen)!=4)
      {
        CONDITIONALERROR(1, pcToken, "VIDEOSTART param are bad");
      }            

      pCommand->SetCommand(TCommand::CM_SYS_VIDEOSTART);
      pCommand->SetVideo(uResX, uResY, uBPP, uFullscreen?true:false);      
    }
    else if (strcmp(pcToken, "VIDEOEND")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_SYS_VIDEOEND);      
    }
    else
    if (strcmp(pcToken, "CLEARON")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_CLEARON);      
    }
    else
    if (strcmp(pcToken, "CLEAROFF")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_CLEAROFF);      
    }
    else
    if (strcmp(pcToken, "MEMBACKBUFFER")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_MEMBACKBUFFER);      
    }
    else
    if (strcmp(pcToken, "VIDEOBACKBUFFER")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_VIDEOBACKBUFFER);      
    }
    else 
    if (strcmp(pcToken, "SKIPTO")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_SKIPTO);
      pcToken=GetToken();
      int iPos=atoi(pcToken);
      pcToken=GetToken();
      int iRow=atoi(pcToken);
      pCommand->SetPosRow(iPos, iRow);            
    }
    else if (strcmp(pcToken, "LOADMP3")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_LOADMP3);

      pcToken=GetToken();   
      pCommand->SetTune(GetTune(pcToken));

      pcToken=GetToken();   
      pCommand->SetArgs(pcToken);              
    }
    else if (strcmp(pcToken, "LOADTRACK")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_LOADTRACK);

      pcToken=GetToken();   
      pCommand->SetTune(GetTune(pcToken));

      pcToken=GetToken();   
      pCommand->SetArgs(pcToken);              
    }
    else if (strcmp(pcToken, "PLAYMUSIC")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_PLAYMUSIC);            

      pcToken=GetToken();   
      pCommand->SetTune(GetTune(pcToken));    

      pcToken=GetToken();
      pCommand->SetLoop((strcmp(pcToken, "LOOP")==0));           
    }
    else if (strcmp(pcToken, "FREEMUSIC")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_FREEMUSIC);      

      pcToken=GetToken();   
      pCommand->SetFx(GetEffect(pcToken));              
    } 
    else if (strcmp(pcToken, "SKIPTOTIME")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");
      pCommand->SetCommand(TCommand::CM_SYS_SKIPTOTIME);
      pcToken=GetToken();
      float fTime=(float)atof(pcToken);
      pCommand->SetTime(fTime);
    }
    else if (strcmp(pcToken, "SYNCTIME")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_SYS_SYNCTIME);
      pcToken=GetToken();
      float fTime=(float)atof(pcToken);
      pCommand->SetTime(fTime);
    }
    else if (strcmp(pcToken, "DUMP")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_SYS_DUMP);           
    }
    else if (strcmp(pcToken, "WAIT")==0)
    {
      pCommand=new TCommand;
      CONDITIONALERROR(pCommand, "Failed to allocate command", "Script Parse Error");      
      pCommand->SetCommand(TCommand::CM_SYS_WAIT);           
      pcToken=GetToken();
      float fTime=(float)atof(pcToken);
      pCommand->SetTime(fTime);
    }
    else
    {
      CONDITIONALERROR(0, pcToken, "Unexpected script command");
    }    

    

	  // Si se ha creado un comando lo anyadimos
	  if (pCommand)
	  {
		  InsertCommandList(pCommand);
	  }
  } 

  m_pCurrentCommand=m_pCommandList;

  
  return (0);
}

void SetRunToMode(bool bRunToMode)
{
  g_bRunToMode = bRunToMode;
}

void SetSound(bool bSound)
{
}

void SetTime(float fTime)
{
  //g_fTime=fTime;
  Timer::SetTime(fTime);
}

float GetTime()
{
  //return (g_fTime);
  return (Timer::GetTime());
}



void ExecuteActiveEffects(int iStartLayer, int iEndLayer, float fDemoTime)
{
  int i;

  for (i=iStartLayer ; i<iEndLayer ; i++)
  {

    // Ejecutamos efectos activos  
    SM_DemoEffectNode*     pEffectNode;
    SM_DemoEffectNode*     pNextNode=0;

    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pEffectNode->pNext)
    {
      pEffectNode->pEffect->RunPreLayer(i, fDemoTime);
    }

    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pNextNode)
    {
      pNextNode=pEffectNode->pNext;
   
      if (pEffectNode->pEffect->m_pParent==0 && pEffectNode->pEffect->m_iLayer==i)
      {
        if (pEffectNode->pEffect->Run(fDemoTime)==0)
        {
          // Si ha acabado lo quitamos de los activos
          pEffectNode->pEffect->Stop();

          RemoveActiveFXList(pEffectNode->pEffect);
        }
      }
    }

    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pEffectNode->pNext)
    {
      pEffectNode->pEffect->RunPostLayer(i, fDemoTime);
    }
  }

}


int RunPreRender    ()
{
  float     fDemoTime=GetTime();

  int i;  
  for (i=0 ; i<MAX_LAYERS ; i++)
  {
    // Ejecutamos efectos activos  
    SM_DemoEffectNode*     pEffectNode;
    SM_DemoEffectNode*     pNextNode=0;
    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pNextNode)
    {
      pNextNode=pEffectNode->pNext;
   
      if (pEffectNode->pEffect->m_pParent==0 && pEffectNode->pEffect->m_iLayer==i)
      {
        pEffectNode->pEffect->RunPreRender(fDemoTime);
      }
    }
  }

  return 0;
}

int RunPostRender   (int iStartLayer, int iEndLayer)
{
  float     fDemoTime=GetTime();

  int i;
  for (i=0 ; i<MAX_LAYERS ; i++)
  {
    // Ejecutamos efectos activos  
    SM_DemoEffectNode*     pEffectNode;
    SM_DemoEffectNode*     pNextNode=0;
    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pNextNode)
    {
      pNextNode=pEffectNode->pNext;
   
      if (pEffectNode->pEffect->m_pParent==0 && pEffectNode->pEffect->m_iLayer==i)
      {
        pEffectNode->pEffect->RunPostRender(fDemoTime);
      }
    }
  }

  return 0;
}

int RunPreStartFrame(int iStartLayer, int iEndLayer)
{
  float     fDemoTime=GetTime();

  int i;
  for (i=iStartLayer ; i<iEndLayer; i++)
  {
    // Ejecutamos efectos activos  
    SM_DemoEffectNode*     pEffectNode;
    SM_DemoEffectNode*     pNextNode=0;
    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pNextNode)
    {
      pNextNode=pEffectNode->pNext;
   
      if (pEffectNode->pEffect->m_pParent==0 && pEffectNode->pEffect->m_iLayer==i)
      {
        pEffectNode->pEffect->RunPreStartFrame(fDemoTime);
      }
    }
  }

  return 0;
}


int RunPostEndFrame (int iStartLayer, int iEndLayer)
{
  float     fDemoTime=GetTime();

  int i;
  for (i=iStartLayer ; i<iEndLayer ; i++)
  {
    // Ejecutamos efectos activos  
    SM_DemoEffectNode*     pEffectNode;
    SM_DemoEffectNode*     pNextNode=0;
    for (pEffectNode=m_pActiveEffects ; pEffectNode ; pEffectNode=pNextNode)
    {
      pNextNode=pEffectNode->pNext;
   
      if (pEffectNode->pEffect->m_pParent==0 && pEffectNode->pEffect->m_iLayer==i)
      {
        pEffectNode->pEffect->RunPostEndFrame(fDemoTime);
      }
    }
  }

  return 0;
}


#define CONDITIONALSKIP(x, error, caption)  {if (!x) { SM_Main::OutputError("%s : %s", error, caption); goto SKIP;}}
int RunCommands()
{
  int iReturn=1;
  TCommand* pCommand;
  
  
  float fTime;
  float fDemoTime=GetTime();  

  bool bContinueProcessing=true;    
  
  if (!m_pCurrentCommand) return 0;

  while (m_pCurrentCommand)
  {
    pCommand=m_pCurrentCommand->pCommand;

    switch (pCommand->GetCommand())
    {      
    case TCommand::CM_FX_START:      
    {
      if (strcmp(pCommand->GetFxName(), "FILTER") == 0)
      {
        SM_Main::OutputDebug("ERROR: Ignoring FXSTART FXFILTER\n");
      }
      else
      {
        SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());      
        RemoveActiveFXList(pEffect);
      
        assert(pEffect);
        SM_Main::OutputConsole("FXSTART %s\n", pCommand->GetFxName());
        InsertActiveFXList(pEffect);

        if (g_bRunToMode)
        {
          pEffect->Start(g_fLastSync);
        }
        else
        {
          pEffect->Start(fDemoTime);      
        }
      }
      break;
    }
    case TCommand::CM_FX_STOP:
    {
      if (strcmp(pCommand->GetFxName(), "FILTER") == 0)
      {
        SM_Main::OutputDebug("ERROR: Ignoring FXSTART FXFILTER\n");
      }
      else
      {
        SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());      
        assert(pEffect);

        RemoveActiveFXList(pEffect);
      
        SM_Main::OutputConsole("FXSTOP %s\n", pCommand->GetFxName());
        pEffect->Stop();          
        
      }
      break;
    }
    case TCommand::CM_FX_LAYER:
    {
      SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());      
      assert(pEffect);
      pEffect->m_iLayer = atoi(pCommand->GetArgs());
    }
    case TCommand::CM_FX_LOAD:
    {
      if (!g_bIgnoreLoads)
      {
        SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());
        if (!pEffect)
        {
          CONDITIONALSKIP(0, pCommand->GetFxName(), "Instance not found");      
        }      
      
        SM_Main::OutputConsole("FXLOAD %s\n", pCommand->GetFxName());
        if (pEffect->Init(pCommand->GetArgs())!=0)
        {
          CONDITIONALSKIP(0, pCommand->GetFxName(), "Error loading");      
        }      
      }
      break;
    }
    case TCommand::CM_FX_SHUT:
    {
      SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());
      assert(pEffect);
      SM_Main::OutputConsole("FXSHUT %s\n", pCommand->GetFxName());
      pEffect->Shutdown();                      
      break;
    }
    case TCommand::CM_FX_COMMAND:
    {
      SM_DemoEffect* pEffect=GetEffect(pCommand->GetFxName());
      assert(pEffect);
      

      if (g_bRunToMode)
      {
        SM_Main::OutputConsole("FXCOMMAND (%.2f) %s %s\n", g_fLastSync, pCommand->GetFxName(), pCommand->GetArgs());

        if (pEffect->Command(g_fLastSync, pCommand->GetArgs())!=0)
        {
          CONDITIONALSKIP(0, pCommand->GetFxName(), "Error sending command to");      
        }        
      }
      else
      {
        SM_Main::OutputConsole("FXCOMMAND (%.2f) %s %s\n", fDemoTime, pCommand->GetFxName(), pCommand->GetArgs());

        if (pEffect->Command(fDemoTime, pCommand->GetArgs())!=0)
        {
          CONDITIONALSKIP(0, pCommand->GetFxName(), "Error sending command to");      
        }        
      }
      
      break;
    }
    case TCommand::CM_SYS_SYNC:     
      int iRow; int iPos;
      pCommand->GetPosRow(iPos, iRow);      
      if (g_iPos>iPos || (g_iPos==iPos && g_iRow>=iRow))
      {  
        SM_Main::OutputConsole("FXSYNC:%03i %03i Sync End\n", iPos, iRow);
        g_bWaitingSync=false;
      }
      else
      {
        bContinueProcessing=false;
        if (!g_bWaitingSync)
        {          
          SM_Main::OutputConsole("FXSYNC:%03i %03i Sync Start\n", iPos, iRow);
          g_bWaitingSync=true;
        }        
      }
      break;
    case TCommand::CM_SYS_SKIPTO:
      {      
        int iPos, iRow;
        pCommand->GetPosRow(iPos, iRow);      
        SkipMusicPosRow(iPos, iRow);
        break;
      }     
        /*
    
    case TCommand::CM_SYS_LOADMUSIC:
      {
      assert(!"Not compatible any more");
      SM_DemoTune* pTune;
      pTune=GetTune(pCommand->GetArgs());
      if (!pTune)
      {
        CONDITIONALSKIP(0, pCommand->GetFxName(), "Tune instance not found");      
      }      

      SM_Main::OutputConsole("LOADMUSIC %s\n", pTune->m_pcInstanceName);
      if (SM_Music::Load(pTune->m_pcBuffer, pTune->m_iLength)==-1)
      {
        CONDITIONALSKIP(0, pTune->m_pcInstanceName, "Error loading tune");      
      }

      g_iPos=-1; g_iRow=-1;
      break;
      }
        */
    
    case TCommand::CM_SYS_STOPMUSIC:      
      StopMusic();
      break;
    case TCommand::CM_SYS_VIDEOSTART:
      #ifdef USEDDRAW
      SM_DDraw::TDisplay Display;

      pCommand->GetVideo(Display.m_uWidth, Display.m_uHeight, Display.m_uBPP, Display.m_bFullScreen);
      SM_Main::OutputConsole("VIDEOSTART %ux%ux%u %s\n",
        Display.m_uWidth, Display.m_uHeight, Display.m_uBPP, Display.m_bFullScreen?"Fullscreen":"Windowed");      
      Display.m_hwnd=SM_Main::Hwnd();
      Display.m_bDoubleBuffer=true;

      if (InitLocalVideo(Display)!=0)
      {
        MessageBox(0, "Failed to init local video", "Error", MB_OK);        
        return(-1);
      }

      if (SM_DDraw::InitDisplay(Display)!=0 && false)
      {
        if (Display.m_uBPP==32)
        {
          // Fallo 32 Bit. Probamos 16. Si funciona la demo vera un framebuffer de 32 bits,
          // pero sera uno de 16 y el sistema manejara las conversiones al vuelo. Nota, las rutinas
          // de conversion son optimizables.

          SM_DDraw::ShutdownDisplay();
          Display.m_uBPP=16;
          if (SM_DDraw::InitDisplay(Display)!=0)
          {
            MessageBox(0, "Failed to init video", "Error", MB_OK);
            SM_Main::OutputConsole("Failed to init video\n",
            Display.m_uWidth, Display.m_uHeight, Display.m_uBPP, Display.m_bFullScreen?"Fullscreen":"Windowed");      
            return (-1);
          }

          g_bForcedHardConversion=true;
          g_bLocalVideo=true; // Forzado para que demo vea 32 bits
        }
        else
        {
          MessageBox(0, "Failed to init video", "Error", MB_OK);
        }
      }      
      #endif
      g_bVideoInit=true;      

      break;
    case TCommand::CM_SYS_VIDEOEND:
      #ifdef USEDDRAW      
      SM_Main::OutputConsole("VIDEOEND\n");
      SM_DDraw::ShutdownDisplay();
      ShutdownLocalVideo();
      #endif
      g_bVideoInit=false;
      break;
    case TCommand::CM_SYS_CLEARON:
      SM_Main::OutputConsole("CLEAR ON\n");
      g_bClearScreen=true;
      break;
    case TCommand::CM_SYS_CLEAROFF:
      SM_Main::OutputConsole("CLEAR OFF\n");
      g_bClearScreen=false;
      break;
    case TCommand::CM_SYS_VIDEOBACKBUFFER:
      SM_Main::OutputConsole("VIDEOBACKBUFFER\n");
      if (!g_bForcedHardConversion) g_bLocalVideo=false;
      break;
    case TCommand::CM_SYS_MEMBACKBUFFER:
      SM_Main::OutputConsole("MEMBACKBUFFER\n");
      g_bLocalVideo=true;
      break;
    case TCommand::CM_SYS_LOADMP3:
      {
        if (!g_bRunToMode)
        {
          SM_DemoTune* pTune;
          pTune=GetTune(pCommand->GetTuneName());
          if (!pTune)
          {
            CONDITIONALSKIP(0, pCommand->GetFxName(), "Tune instance not found");      
          }      

          SM_Main::OutputConsole("LOADMP3 %s %s\n", pTune->m_pcInstanceName, pCommand->GetArgs());

          char pcPath[MAX_PATH];
          strcpy(pcPath, "data/Music/");
          strcat(pcPath, pCommand->GetArgs());
          if (pTune->Load(pcPath)!=0)
          {
            CONDITIONALSKIP(0, pcPath, "Error loading Music");      
          }

        
          pTune->m_Flags|=SM_DemoTune::E_MP3;

          g_fMP3Time=-1.0f;
        }
        break;
      }
    case TCommand::CM_SYS_LOADTRACK:
      {
        if (!g_bRunToMode)
        {
          SM_DemoTune* pTune;
          pTune=GetTune(pCommand->GetTuneName());
          if (!pTune)
          {
            CONDITIONALSKIP(0, pCommand->GetFxName(), "Tune instance not found");      
          }      

          SM_Main::OutputConsole("LOADMP3 %s %s\n", pTune->m_pcInstanceName, pCommand->GetArgs());

          char pcPath[MAX_PATH];
          strcpy(pcPath, "data/Music/");
          strcat(pcPath, pCommand->GetArgs());
          if (pTune->Load(pcPath)!=0)
          {
            CONDITIONALSKIP(0, pcPath, "Error loading Music");      
          }        

          pTune->m_Flags|=SM_DemoTune::E_TRACK;

          g_fMP3Time=-1.0f;
          break;
        }
      }

    case TCommand::CM_SYS_PLAYMUSIC:
      if (!g_bRunToMode)
      {
        SM_DemoTune* pTune;
        pTune=GetTune(pCommand->GetTuneName());
        if (!pTune)
        {
          CONDITIONALSKIP(0, pCommand->GetFxName(), "Tune instance not found");      
        } 
      
        SM_Main::OutputConsole("PLAYMUSIC %s\n", pCommand->GetTuneName());

        if (PlayMusic(pTune, pCommand->GetLoop())!=0)
        {
          CONDITIONALSKIP(0, pCommand->GetTuneName(), "Failed to play tune");      
        }
      
        break;
      }


    case TCommand::CM_SYS_FREEMUSIC:
      if (!g_bRunToMode)
      {
        SM_DemoTune* pTune;
        pTune=GetTune(pCommand->GetTuneName());
        if (!pTune)
        {
          CONDITIONALSKIP(0, pCommand->GetTuneName(), "Tune instance not found");      
        } 

        pTune->Free();

        break;
      }
    case TCommand::CM_SYS_SKIPTOTIME:
      if (!g_bRunToMode)
      {
        SM_Main::OutputConsole("SKIPTOTIME %.2f\n", pCommand->GetTime());      
        SkipMusicTime(pCommand->GetTime());      
      }
      break;
    case TCommand::CM_SYS_WAIT:
      fTime=pCommand->GetTime();      
      if (g_bWaitingSync && fTime && GetTime()>=g_fWaitTime+fTime)
      {  
        SM_Main::OutputConsole("WAIT %f End\n", fTime);
        
        g_bWaitingSync=false;        

        SetLastSyncPoint(g_fLastSync+fTime);
      }
      else
      {
        g_bRunToMode = false;
        bContinueProcessing=false;
        if (!g_bWaitingSync)
        {          
          SM_Main::OutputConsole("WAIT: %.2f Start\n", fTime);
          g_bWaitingSync=true;
          g_fWaitTime=GetTime();
        }        
      }
      break;

    case TCommand::CM_SYS_SYNCTIME:
      fTime;
      fTime=pCommand->GetTime();      
      if (GetTime() >= fTime )
      {  
        SM_Main::OutputConsole("FXSYNC: %.2f Sync End\n", fTime);
        g_bWaitingSync=false;        

        SetLastSyncPoint(fTime);
      }
      else
      {
        g_bRunToMode = false;
        bContinueProcessing=false;
        if (!g_bWaitingSync)
        {          
          SM_Main::OutputConsole("FXSYNC: %.2f Sync Start\n", fTime);
          g_bWaitingSync=true;
        }        
      }
      
      break;
    case TCommand::CM_SYS_DUMP:
      bContinueProcessing=false;
      m_pCurrentCommand=m_pCurrentCommand->pNext;    
      SM_Main::OutputConsole("DUMP\n", fTime);
      break;
    default:
      return (-1);
      
    }

    if (!bContinueProcessing)
    {
      break;
    }
    
SKIP:
    
    m_pCurrentCommand=m_pCurrentCommand->pNext;
    if (!m_pCurrentCommand)
    {
      if (m_bLooped)
      {
        m_pCurrentCommand=m_pCommandList;
        break;
      }      
      else
      {
        iReturn = 0;
      }
    }
  }

  return iReturn;
}


int Run(int iStartLayer, int iEndLayer)
{
  
  float     fDemoTime=GetTime();
  
  int  iReturn=1;

  
  if (!g_bActive)
  {
    return 1;
  }
  

  // MP3 Time
  if (g_bMP3Play)
  {
    g_fMP3Time=SM_Music::MP3Time();
  }
  
  
  RunPreRender();

  // Si hay video nuevo frame    
  #ifdef USEDDRAW  
  if (g_bVideoInit)
  {
    if (Keyboard.IsPressed(VK_RETURN))
    {
      SM_DDraw::ToggleFullscreen();
    }
    SM_DDraw::InitFrame(g_bVideoRestore);  
    
    SM_DDraw::TLockData LockData;

    SM_DDraw::TPixelFormat PixelFormat;
    SM_DDraw::PixelFormat(true, PixelFormat);
    
    if (SM_DDraw::Lock(true, LockData)==0)
    {       
      CVideoBufferDataFromDDraw(SM_DEData::VideoBuffer, LockData, PixelFormat);      

      if (g_bVideoRestore)
      {
        g_bForcedHardConversion=PixelFormat.m_uBPP==g_sLocalVideo.m_uBPP?false:true;
        g_bVideoRestore=false;
      }
      


      if (g_bLocalVideo || g_bForcedHardConversion)
      {     
        memcpy(&SM_DEData::VideoBuffer, &g_sLocalVideo, sizeof(SM_DEData::VideoBuffer));        
      }
      else
      {
        SM_DEData::VideoBuffer.m_pVideo=LockData.m_pSurfaceData;            
      }

      // Borramos pantalla
      if (g_bClearScreen)
      {
        unsigned i;
        char* pBuffer=(char*)SM_DEData::VideoBuffer.GetSurfacePointer();
        for (i=0 ; i<SM_DEData::VideoBuffer.m_uHeight ; i++)
        {
          memset(pBuffer, 0, SM_DEData::VideoBuffer.m_uWidth*
                (SM_DEData::VideoBuffer.m_uBPP>>3));
          pBuffer+=SM_DEData::VideoBuffer.m_uByteStride;
        }        
      }
            
      ExecuteActiveEffects(fDemoTime);

      if (g_bLocalVideo )
      {
        // Volcado
        // TODO
        /*
        MSurface FrameBuffer;
        FrameBuffer.Init(sd, LockData.m_pSurfaceData,0,0);

        FrameBuffer.ConvertFrom(g_sLocalVideo);
        */
        if (g_bForcedHardConversion)
        {
          // Conversion 32->16
          if (PixelFormat.m_uRBitMask==0x0000F800 &&
              PixelFormat.m_uGBitMask==0x000007E0 &&
              PixelFormat.m_uBBitMask==0x0000001F)
          {              
          #ifndef USE_MMX
          ConvertA0R8G8B8toR5G6B5  (LockData.m_pSurfaceData, LockData.m_uStride, 
                                     g_sLocalVideo.GetSurfacePointer(),  g_sLocalVideo.m_uByteStride,
                                     g_sLocalVideo.m_uWidth,
                                     g_sLocalVideo.m_uHeight);
          
          #else
          ConvertA0R8G8B8toR5G6B5MMX(LockData.m_pSurfaceData, LockData.m_uStride, 
                                     g_sLocalVideo.GetSurfacePointer(),  g_sLocalVideo.m_uByteStride,
                                     g_sLocalVideo.m_uWidth,
                                     g_sLocalVideo.m_uHeight);
          #endif
          }

          if (PixelFormat.m_uRBitMask==0x00007C00 &&
              PixelFormat.m_uGBitMask==0x000003E0 &&
              PixelFormat.m_uBBitMask==0x0000001F)
          {              
          #ifndef USE_MMX
          ConvertA0R8G8B8toR5G5B5 (LockData.m_pSurfaceData, LockData.m_uStride, 
                                   g_sLocalVideo.GetSurfacePointer(),  g_sLocalVideo.m_uByteStride,
                                   g_sLocalVideo.m_uWidth,
                                   g_sLocalVideo.m_uHeight);
          #else
          ConvertA0R8G8B8toR5G5B5MMX(LockData.m_pSurfaceData, LockData.m_uStride, 
                                     g_sLocalVideo.GetSurfacePointer(),  g_sLocalVideo.m_uByteStride,
                                     g_sLocalVideo.m_uWidth,
                                     g_sLocalVideo.m_uHeight);
          #endif
          }
        }
        else 
        {
          unsigned i;
          for (i=0 ; i<g_sLocalVideo.m_uHeight ; i++)
          {
            memcpy
              (
               ((char*)LockData.m_pSurfaceData)+i*LockData.m_uStride,
               g_sLocalVideo.GetSurfacePointer(0, i),
              (g_sLocalVideo.m_uBPP>>3)*g_sLocalVideo.m_uWidth
              );
          }          
        }
      }      

      SM_DDraw::Unlock(true);    
    }

    
    static FLOAT fFPS      = 0.0f;
    static FLOAT fLastTime = 0.0f;
    static DWORD dwFrames  = 0L;

	  FLOAT fTime = GetTime() * 0.001f; // Get current time in seconds
	  ++dwFrames;

	  // Update the frame rate once per second
  	if( fTime - fLastTime > 1.0f )
    {
        fFPS      = (float)dwFrames*(fTime - fLastTime);
        fLastTime = fTime;
        dwFrames  = 0L;
    }

    if (g_bDrawFPS)
    {
      SM_DDraw::Printf(0, 16, 0xFFFF00, "FPS : %.0f", fFPS);    
      SM_DDraw::Printf(0, 0, 0xFFFF00, "Pos: %i Row: %i", g_iPos, g_iRow);    
      SM_DDraw::Printf(0, 32, 0xFFFF00, "TIME: %.2f" , fDemoTime);    
      SM_DDraw::Printf(0, 64, 0xFFFF00, "BB: %s" , g_bLocalVideo?"RAM":"VIDEO");    
      SM_DDraw::Printf(0, 80, 0xFFFF00, "Clear: %s", g_bClearScreen?"ON":"OFF");
    }
          
    SM_DDraw::EndFrame();    
  }
  #else
  ExecuteActiveEffects(iStartLayer, iEndLayer, fDemoTime);
  #endif

  RunPostRender(iStartLayer, iEndLayer);


  
  if (g_bVideoInit)
  {
    
  }
  
  
  
  return (iReturn);
}

SM_DemoTune*   GetTune(const char* pcName)
{
  SM_DemoTune* pTune;

  for (pTune=SM_DemoTune::TuneInstances; pTune ; pTune=pTune->m_pNextTune)
  {
    if (strcmp(pTune->m_pcInstanceName, pcName)==0)
    {
      return (pTune);
    }
  }

  return (0);
}


int StopMusic()
{
  assert(g_pPlayingTune);
  if (!g_pPlayingTune)
  {
    return -1;
  }

  if (g_pPlayingTune->m_Flags & SM_DemoTune::E_MP3)
  {
    SM_Music::Stop();
    SM_Music::Free();
    g_pPlayingTune=0;
    g_bMP3Play=false;
  }
  else if (g_pPlayingTune->m_Flags & SM_DemoTune::E_TRACK)
  {
          SM_Music::MP3Stop();
    SM_Music::MP3Free();
    g_pPlayingTune=0;
  }

  return 0;
}

int PlayMusic(SM_DemoTune* pTune, bool bLooped)
{
  if (g_pPlayingTune)
  {
    StopMusic();
  }

  if (pTune->m_Flags & SM_DemoTune::E_TRACK)
  {
    if (SM_Music::Load(pTune->m_pcBuffer, pTune->m_iLength)==-1)
    {
      return -1;
    }              

    SM_Music::SetEventHandler(&Music); 
    g_iPos=-1; g_iRow=-1;
    SM_Music::Play(bLooped);          
  }
  else
  {
    if (SM_Music::MP3Load(pTune->m_pcBuffer, pTune->m_iLength)==-1)
    {      
      return -1;
    }
    
    SM_Music::MP3Play();
    g_fMP3Time=-1.0f;
    g_bMP3Play=true;
  }

  g_pPlayingTune=pTune;
  
  return 0;
}



int SkipMusicTime(float fTime)
{
  assert(g_pPlayingTune && (g_pPlayingTune->m_Flags& SM_DemoTune::E_MP3));
  if (!g_pPlayingTune || (g_pPlayingTune->m_Flags& SM_DemoTune::E_MP3)==0)
  {
    return -1;
  }

  SM_Music::MP3PlayEx(fTime);  

  return 0;
}

int SkipMusicPosRow(int iPos, int iRow)
{
  assert(g_pPlayingTune && (g_pPlayingTune->m_Flags& SM_DemoTune::E_TRACK));
  if (!g_pPlayingTune || (g_pPlayingTune->m_Flags& SM_DemoTune::E_TRACK)==0)
  {
    return -1;
  }
  SM_Music::PlayEx(iPos, iRow);        

  return 0;
}

void InsertCommandList(TCommand*     pCommand)
{
  TCommandNode* pNewNode;
	pNewNode=new TCommandNode;
	pNewNode->pCommand=pCommand;
	pNewNode->pNext   =0;

	if (m_pCommandList)
	{
		m_pCommandListLastNode->pNext = pNewNode;
    m_pCommandListLastNode = pNewNode;
	}
	else
	{
		m_pCommandList = m_pCommandListLastNode = pNewNode;
	}
}

void ShutdownCommandList()
{
  TCommandNode* pCommandNode;
  TCommandNode* pNextCommandNode;

  for (pCommandNode=m_pCommandList ;  pCommandNode ; pCommandNode=pNextCommandNode)
  {
    pNextCommandNode=pCommandNode->pNext;
	  delete pCommandNode->pCommand;
	  delete pCommandNode;
  }
  m_pCommandList = 0;
  m_pCommandListLastNode = 0;
}

TCommandNode* GetCommandList()
{
  return m_pCommandList;
}


} //namespace SM_DemoScript



