void VShadowMapGenSpotDir::Update(bool force)
{
  VisContextCamera_cl *pMainCam = m_pRendererNode->GetReferenceContext()->GetCamera();
  VASSERT(pMainCam);
  float fCamAngle = hkvMath::Abs (hkvMath::acosDeg (pMainCam->GetDirection().dot (m_vLastCameraDir)));
  hkvVec3 vCamMove = pMainCam->GetPosition() - m_vLastCameraPos;
  m_pRendererNode->GetReferenceContext()->GetViewFrustum(m_MainViewFrustum);

  float fFovX, fFovY;
  m_pRendererNode->GetReferenceContext()->GetFinalFOV(fFovX, fFovY);

  float fNear, fFar;
  m_pRendererNode->GetReferenceContext()->GetClipPlanes(fNear, fFar);

  VBaseShadowMapComponentSpotDirectional* pComponent = static_cast<VBaseShadowMapComponentSpotDirectional*>(m_pShadowComponent);

  if (m_eProjectionType == SHADOW_PROJECTION_ORTHOGRAPHIC)
  {
    bool bOverestimateCascades = pComponent->GetOverestimateCascades() ? true : false;
    if (bOverestimateCascades)
    {
      if (m_fFovX != fFovX || m_fFovY != fFovY || m_fNear != fNear)
      {
        // In case user switches the FOV at runtime we need to update it here
        float fStartDistance = fNear;
        for (int iCascade = 0; iCascade < m_iNumParts; iCascade++)
        {
          float fEndDistance = pComponent->GetCascadeRange(iCascade) + fNear;
          m_pParts[iCascade].ComputeOffset(fStartDistance, fEndDistance);
          fStartDistance = fEndDistance;
        }

        m_fFovX = fFovX;
        m_fFovY = fFovY;
        m_fNear = fNear;
        force = true;
      }

      if (force || m_vLastLightPos != m_pLightSource->GetPosition() || 
        m_vLastLightDir != m_pLightSource->GetDirection() || 
        vCamMove.getLength() > pComponent->GetShadowMapCameraUpdateInterval() || 
        fCamAngle > pComponent->GetShadowMapCameraUpdateAngle())
      {
        for (int iCascade = 0; iCascade < m_iNumParts; iCascade++)
        {
          VShadowMapPart& part = m_pParts[iCascade];
          
          VisContextCamera_cl* pCam = part.GetRenderContext()->GetCamera();
          VisContextCamera_cl *pReferenceCam = m_pRendererNode->GetReferenceContext()->GetCamera();

          hkvVec3 vCascadeCenter = pReferenceCam->GetPosition() + pReferenceCam->GetDirection() * part.m_fCenterOffset;
          pCam->SetDirection(GetDirection());

          float fRadius = part.m_fRadius + pComponent->GetShadowMapCameraUpdateInterval();

          float fCameraDistanceFromCenter = fFar;
          hkvVec3 vCamPos = vCascadeCenter - GetDirection() * fCameraDistanceFromCenter;
          pCam->SetPosition(vCamPos);

          //snapping
          hkvVec3 offset = pCam->GetWorldToCameraTransformation().getColumn(3).getAsVec3();

          float fPixelSize = (fRadius * 2) / (float)m_pShadowComponent->GetShadowMapSize();
          offset.x -= floorf(offset.x / fPixelSize) * fPixelSize;
          offset.y -= floorf(offset.y / fPixelSize) * fPixelSize;
          
          vCamPos -= pCam->GetObjDir_Right() * offset.x - pCam->GetObjDir_Up() * offset.y;
          pCam->SetPosition(vCamPos);
          
          
          // Set far clip plane so that we have z = 1 at the far side of the sphere - the shader expects this when using the BoundingBox cascade selection method.
          part.GetRenderContext()->SetClipPlanes(0.0f, fCameraDistanceFromCenter + fRadius);
          part.GetRenderContext()->SetOrthographicSize(fRadius * 2, fRadius * 2);
          part.Update();
        }

        m_vLastLightPos = m_pLightSource->GetPosition();
        m_vLastLightDir = m_pLightSource->GetDirection();
        m_vLastCameraPos = pMainCam->GetPosition();
        m_vLastCameraDir = pMainCam->GetDirection();
      }
    }
    else
    {
      float fStartDistance = 0.0f;
      for (int iCascade = 0; iCascade < m_iNumParts; iCascade++)
      {
        VShadowMapPart& part = m_pParts[iCascade];
        VisContextCamera_cl* pCam = part.GetRenderContext()->GetCamera();

        // TODO: Performance

        // Compute the extremes of the view frustum fragment for this cascade
        hkvVec3 vCorners[8];
        float fEndDistance = pComponent->GetCascadeRange(iCascade);
        part.m_fCullDistance = fEndDistance;
        part.GetViewFrustumCornersAtDistance(m_pRendererNode->GetReferenceContext(), fStartDistance, &vCorners[0]);
        part.GetViewFrustumCornersAtDistance(m_pRendererNode->GetReferenceContext(), fEndDistance,   &vCorners[4]);
        fStartDistance = fEndDistance;

        pCam->SetDirection(GetDirection());
        float fMinRight = FLT_MAX;
        float fMinUp = FLT_MAX;
        float fMaxRight = -FLT_MAX;
        float fMaxUp = -FLT_MAX;
        float fMinDist = FLT_MAX;
        float fMaxDist = -FLT_MAX;
        for (int iCorner = 0; iCorner < 8; iCorner ++ )
        {
          float fRight = pCam->GetObjDir_Right().dot (vCorners[iCorner]);
          if (fRight < fMinRight)
            fMinRight = fRight;
          if (fRight > fMaxRight)
            fMaxRight = fRight;

          float fUp = pCam->GetObjDir_Up().dot (vCorners[iCorner]);
          if (fUp < fMinUp)
            fMinUp = fUp;
          if (fUp > fMaxUp)
            fMaxUp = fUp;

          float fDist = pCam->GetDirection().dot (vCorners[iCorner]);
          if (fDist < fMinDist)
            fMinDist = fDist;
          if (fDist > fMaxDist)
            fMaxDist = fDist;
        }

        // Since we need to take geometry into account which lies in front of the view frustum, we need to
        // offset the near clip plane (in this case, the camera position) away from the view frustum
        fMinDist -= (fFar - fNear);

        hkvVec3 vCamPos = pCam->GetObjDir_Right() * ((fMinRight + fMaxRight)*0.5f) 
          + pCam->GetObjDir_Up() * ((fMinUp + fMaxUp)*0.5f)
          + pCam->GetDirection() * fMinDist;

        float fPadding = pComponent->GetShadowMapCameraUpdateInterval();
        pCam->SetPosition(vCamPos);
        part.GetRenderContext()->SetClipPlanes(0.0f, fMaxDist - fMinDist);
        part.GetRenderContext()->SetOrthographicSize(fMaxRight - fMinRight + fPadding, fMaxUp - fMinUp + fPadding);

        part.Update();
      }
    }
  }
  else if (m_eProjectionType == SHADOW_PROJECTION_PERSPECTIVE)
  {
    if (m_pLightSource->GetRadius() <= 0) //this is the case if triggered is set to false for the light
    {
      return; //do render the light at all
    }

    if (force || m_vLastLightPos != m_pLightSource->GetPosition() || m_vLastLightDir != m_pLightSource->GetDirection() ||
      m_fLastRadius != m_pLightSource->GetRadius() || m_fLastAngle != m_pLightSource->GetProjectionAngle())
    {
      VShadowMapPart& part = m_pParts[0];
      VisContextCamera_cl* pCam = part.GetRenderContext()->GetCamera();

      pCam->SetDirection(GetDirection());
      pCam->SetPosition(GetPosition());
      part.GetRenderContext()->SetClipPlanes(m_pShadowComponent->GetNearClip(), m_pLightSource->GetRadius());
      float fAngle = m_pLightSource->GetProjectionAngle();
      part.GetRenderContext()->SetFOV(fAngle, fAngle);

      part.Update();

      m_vLastLightPos = m_pLightSource->GetPosition();
      m_vLastLightDir = m_pLightSource->GetDirection();
      m_fLastRadius = m_pLightSource->GetRadius();
      m_fLastAngle = fAngle;
    }
  }

  m_iPartsRendered = 0;
}