void RPG_MeshTrailEffectComponent::UpdateHistory(float fAbsTime)
{
  m_historyCount = hkvMath::Min(m_historyCount + 1, m_numSegments);
  m_historyPos = (m_historyPos + 1) % m_numSegments;
  VTrailHistoryEntry &entry( m_history[m_historyPos] );

  VisObject3D_cl *pObj = (VisObject3D_cl *)GetOwner();
  hkvMat3 rotation = pObj->GetRotationMatrix();
  const hkvVec3 &vPos(pObj->GetPosition());

  entry.m_start = rotation.transformDirection(m_relStart);
  entry.m_end = rotation.transformDirection(m_relEnd);
  entry.m_start += vPos;
  entry.m_end += vPos;

  entry.m_time = fAbsTime;
}
void VTimeOfDayComponent::UpdateParent()
{
  IVTimeOfDay *pTimeOfDayInterface = Vision::Renderer.GetTimeOfDayHandler();
  if (pTimeOfDayInterface == NULL)
    return;

  VisObject3D_cl *pOwnerObject = (VisObject3D_cl *)m_pOwner;
  VASSERT(pOwnerObject);

  hkvVec3 vDirection(hkvNoInitialization);
  pTimeOfDayInterface->GetSunDirection(vDirection);
  vDirection.normalizeIfNotZero();

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE)
  {
    vDirection = -vDirection; 
  }
  else if(AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE)
  {
    vDirection.x = -vDirection.x;
    vDirection.y = -vDirection.y;
  }
  
  if (AttachmentType != TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE)
  {
    pOwnerObject->SetDirection(vDirection);
  }

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
  {
    // TODO (multiple renderer nodes)
    IVRendererNode *pRenderer = Vision::Renderer.GetRendererNode(0);
    float fNear, fFar;
    pRenderer->GetReferenceContext()->GetClipPlanes(fNear, fFar);
    hkvVec3 vCamPos = pRenderer->GetReferenceContext()->GetCamera()->GetPosition();

    hkvVec3 vCoronaPos = -vDirection;
    vCoronaPos *= 0.95f * fFar;
    vCoronaPos += vCamPos;
    pOwnerObject->SetPosition(vCoronaPos);
  }

  if (m_bIsLightClass)
  {
    VisLightSource_cl *pLight = (VisLightSource_cl*)m_pOwner;
    VColorRef sunColor = pTimeOfDayInterface->GetSunColor();

    bool bSwitchable = (AttachmentType == TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE);
    float fBelowHorizonMultiplier = hkvMath::pow (hkvMath::Max(-vDirection.z+0.1f, 0.0f), bSwitchable ? 1.0f : 0.1f);
    fBelowHorizonMultiplier = hkvMath::Min(1.0f, fBelowHorizonMultiplier);

    if (bSwitchable && fBelowHorizonMultiplier < 1.0f && fBelowHorizonMultiplier > 0.f)
    {
      pLight->SetColor(m_iColor);
      pLight->SetMultiplier(Intensity * (1.0f - fBelowHorizonMultiplier));
    }
    else if (AttachmentType == TIMEOFDAY_ATTACHMENT_SUNLIGHTSOURCE)
    {
      pLight->SetColor(sunColor);
      pLight->SetMultiplier(Intensity * fBelowHorizonMultiplier);
    }
    else if ((AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE) ||
             (AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE))
    {
      // TODO
      VColorRef negativeColor = V_RGBA_WHITE - sunColor;
      pLight->SetColor(negativeColor);
      pLight->SetMultiplier(Intensity * fBelowHorizonMultiplier * 0.333f);
    }  
    else if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
    {
      hkvVec3 vSunColorFloat = sunColor.ToFloat();
      float fLargestComponent = hkvMath::Max(hkvMath::Max(vSunColorFloat.x, vSunColorFloat.y), vSunColorFloat.z);
      if (fLargestComponent <= 0.0f)
        fLargestComponent = 1.0f;
      sunColor.FromFloat(vSunColorFloat * (1.0f / fLargestComponent));

      pLight->SetColor(sunColor * fBelowHorizonMultiplier);
      pLight->SetMultiplier(0.0f);
    }
  }
}
void VFmodManager::RunTick(float fTimeDelta)
{
  VISION_PROFILE_FUNCTION(PROFILING_FMOD_OVERALL);

  if (!IsInitialized())
  {
    if (!IsOutputDevicePresent())
      InitDevice();

    return; 
  }

  // profiling scope
  {
    VISION_PROFILE_FUNCTION(PROFILING_FMOD_PUREUPDATE);

    VASSERT(m_pEventSystem!=NULL);

    // update Fmod listener attributes
    VisObject3D_cl *pListener = m_pListenerObject;
    if (pListener == NULL)
    {
      // The listener is the main camera. Check for teleportation since the last Fmod update, in
      // which case we won't use the position difference to calculate the listener speed.
      VisContextCamera_cl* pCamera = Vision::Camera.GetMainCamera();
      VisRenderContext_cl* pContext = VisRenderContext_cl::GetMainRenderContext();
      if (pCamera != NULL && pContext != NULL)
      {
        if (m_bLastListenerPositionValid && pCamera->GetLastTeleported() > m_iFrameOfLastUpdate)
          m_bLastListenerPositionValid = false;

        m_iFrameOfLastUpdate = pContext->GetLastRenderedFrame();
        pListener = pCamera;
      }
    }

    if (!pListener)
      return;

    hkvVec3 vCamPos = pListener->GetPosition();
    hkvVec3 vDir(pListener->GetObjDir()),
            vRight(pListener->GetObjDir_Right()),
            vUp(pListener->GetObjDir_Up());

    // Determine the camera velocity based on the previous known position
    hkvVec3 vCamVel(m_bLastListenerPositionValid && (fTimeDelta > 0.f) ? (vCamPos - m_vLastListenerPosition) * (1.f / fTimeDelta) : hkvVec3::ZeroVector());
    m_vLastListenerPosition = vCamPos;
    m_bLastListenerPositionValid = true;

    vUp = -vUp; // compensate for coordinate system
    m_pEventSystem->set3DListenerAttributes(0, (FMOD_VECTOR *)&vCamPos, (FMOD_VECTOR *)&vCamVel, (FMOD_VECTOR *)&vDir, (FMOD_VECTOR *)&vUp);

    // update all sound objects 
    SoundInstances().Update(fTimeDelta);

    // update all events 
    Events().Update(fTimeDelta);

    // update Fmod event system
    m_fTimeLeftOver += fTimeDelta;
    if (m_fTimeLeftOver > m_config.fTimeStep)
    { 
      m_pEventSystem->update();

#ifdef VFMOD_SUPPORTS_NETWORK
      if (m_config.bUseNetworkSystem)
        FMOD::NetEventSystem_Update();
#endif
      m_fTimeLeftOver = hkvMath::mod (m_fTimeLeftOver, m_config.fTimeStep);
    }
  }

  // do not purge sounds/ events in vForge, in order to allow toggling playback via hotspot button
  if (Vision::Editor.IsInEditor())
    return;  

  if (m_bAnyStopped)
  {
    VISION_PROFILE_FUNCTION(PROFILING_FMOD_PURGE);

    // all sounds/ events that have finished playing are removed from handling
    SoundInstances().PurgeNotPlaying();
    Events().PurgeNotPlaying();

    m_bAnyStopped = false; // reset any stopped flag
  }
}
void VFmodManager::RunTick(float fTimeDelta)
{
  if (!IsInitialized())
    return;

  VISION_PROFILE_FUNCTION(PROFILING_FMOD_OVERALL);

  // profiling scope
  {
    VISION_PROFILE_FUNCTION(PROFILING_FMOD_PUREUPDATE);

    VASSERT(m_pEventSystem!=NULL);
    
    // update Fmod listener attributes
    VisObject3D_cl *pListener = m_pListenerObject ? m_pListenerObject : Vision::Camera.GetMainCamera();
    if (!pListener)
      return;

    hkvVec3 vCamPos = pListener->GetPosition();
    hkvVec3 vDir(pListener->GetObjDir()),
            vRight(pListener->GetObjDir_Right()),
            vUp(pListener->GetObjDir_Up());

    vUp = -vUp; // compensate for coordinate system
    m_pEventSystem->set3DListenerAttributes(0, (FMOD_VECTOR *)&vCamPos, NULL, (FMOD_VECTOR *)&vDir, (FMOD_VECTOR *)&vUp); // no speed (yet)
    
    
    // update all sound objects 
    SoundInstances().Update();

    // update all events 
    Events().Update();

    // update Fmod event system
    m_fTimeLeftOver += fTimeDelta;
    if (m_fTimeLeftOver > m_config.fTimeStep)
    { 
      m_pEventSystem->update();
#ifdef VFMOD_SUPPORTS_NETWORK
      if (m_config.bUseNetworkSystem)
        FMOD::NetEventSystem_Update();
#endif
      m_fTimeLeftOver = hkvMath::mod (m_fTimeLeftOver, m_config.fTimeStep);
    }
  } 
  
  // do not purge sounds/ events in vForge, in order to allow toggling playback via hotspot button
  if (Vision::Editor.IsInEditor())
    return;  

  if (m_bAnyStopped)
  {
    VISION_PROFILE_FUNCTION(PROFILING_FMOD_PURGE);

    // all sounds/ events that have finished playing are removed from handling
    SoundInstances().PurgeNotPlaying();
    Events().PurgeNotPlaying();

    m_bAnyStopped = false; // reset any stopped flag
  }
}
void VTimeOfDayComponent::UpdateParent()
{
  VTimeOfDay *pTimeOfDayInterface = (VTimeOfDay*)Vision::Renderer.GetTimeOfDayHandler();
  if (pTimeOfDayInterface == NULL)
    return;

  VisObject3D_cl *pOwnerObject = (VisObject3D_cl *)m_pOwner;
  VASSERT(pOwnerObject);

  hkvVec3 vDirection(hkvNoInitialization);
  pTimeOfDayInterface->GetSunDirection(vDirection);

  // The Moon and back light direction is calculated from the Sun direction
  if (AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE)
  {
    vDirection = -vDirection; 
  }
  else if(AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE)
  {
    vDirection.x = -vDirection.x;
    vDirection.y = -vDirection.y;
  }
  
  if (AttachmentType != TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE)
  {
    pOwnerObject->SetDirection(vDirection);
  }

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
  {
    // TODO (multiple renderer nodes)
    IVRendererNode *pRenderer = Vision::Renderer.GetRendererNode(0);
    float fNear, fFar;
    pRenderer->GetReferenceContext()->GetClipPlanes(fNear, fFar);
    hkvVec3 vCamPos = pRenderer->GetReferenceContext()->GetCamera()->GetPosition();

    hkvVec3 vCoronaPos = -vDirection;
    vCoronaPos *= 0.95f * fFar;
    vCoronaPos += vCamPos;
    pOwnerObject->SetPosition(vCoronaPos);
  }

  // Set the color and intensity of the light
  if (m_bIsLightClass)
  {
    VisLightSource_cl *pLight = (VisLightSource_cl*)m_pOwner;
    VColorRef color;
    float intensity = 0.0f;

    switch (AttachmentType)
    {
    case TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE:
      {
        color = m_iColor;
        const float fMarginNearHorizon = 0.1f; //10% - Margin above the horizon to switch lights ON/OFF
        const float fBelowHorizonMultiplier = hkvMath::Max(-vDirection.z + fMarginNearHorizon, 0.0f);
        intensity = 1.0f - hkvMath::Min(1.0f, fBelowHorizonMultiplier);
        break;
      }
    case TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetSunColor();
        hkvVec3 vSunColorFloat = color.ToFloat();
        float fLargestComponent = hkvMath::Max(hkvMath::Max(vSunColorFloat.x, vSunColorFloat.y), vSunColorFloat.z);
        if (fLargestComponent > 0.0f)
        {
          color.FromFloat(vSunColorFloat / fLargestComponent);
        }      
        intensity = 0.0f;
        break;
      }
    case TIMEOFDAY_ATTACHMENT_SUNLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetSunColor();
        intensity = pTimeOfDayInterface->GetSunIntensity();
        break;
      }
    case TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetBackLightColor();
        intensity = pTimeOfDayInterface->GetBackLightIntensity();
        break;
      }
    case TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetMoonColor();
        intensity = pTimeOfDayInterface->GetMoonIntensity();
        break;
      }
    default:
      VASSERT_MSG(0,"Unknown time of day attachment type");
    }

    pLight->SetColor(color);
    pLight->SetMultiplier(intensity * Intensity);    
  }
}