void VDebugOptions::OnHandleCallback(IVisCallbackDataObject_cl* pData)
{
  if (pData->m_pSender == &Vision::Callbacks.OnUpdateSceneBegin)
  {
#if defined(WIN32)
    if (GetParent()->GetInputMap()->GetTrigger(TOGGLE_FPS))
    {
      SetFrameRateVisible(!IsFrameRateVisible());
    }
    else if (GetParent()->GetInputMap()->GetTrigger(TOGGLE_WIREFRAME))
    {
      SetWireframe(!IsWireframe());
    }
#endif

    // FPS accumulation
    {
      m_iFrameCounter++;
      m_fTimeAccumulator += Vision::GetUITimer()->GetTimeDifference();

      if (m_fTimeAccumulator >= 1.0f)
      {
        m_fCurrentFrameTime = m_fTimeAccumulator / m_iFrameCounter;
        m_fCurrentFps = m_iFrameCounter / m_fTimeAccumulator;

        m_fTimeAccumulator = 0.0f;
        m_iFrameCounter = 0;
      }
    }

    if (m_bFpsVisible)
      Vision::Message.Print(1, 10, Vision::Video.GetYRes() - 35, "FPS : %.1f\nFrame Time : %.2f", m_fCurrentFps, m_fCurrentFrameTime * 1000.0f);
  }
  else if (pData->m_pSender == &Vision::Callbacks.OnBeforeSwapBuffers)
  {
    if (m_bSaveScreenshot)
    {
      VScreenShotHelper helper;
      helper.Capture();
      if (helper.PendingDataInBuffer())
      {
        if (helper.SaveBufferToFile("", NULL, 1.0f, 1.0f))
          Vision::Message.Add(0, "Screenshot saved to \"%s\".\n", helper.GetScreenShotPath());
        else
          Vision::Message.Add(0, "Screenshot could not be saved.\n");
      }

      // Re-enable the VAppMenu again
      VAppMenu* pMainMenu = GetParent()->GetAppModule<VAppMenu>();
      if (pMainMenu)
        pMainMenu->SetVisible(true);

      m_bSaveScreenshot = false;
    }
  }
  else if (pData->m_pSender == &Vision::Callbacks.OnRenderHook)
  {
    VisRenderHookDataObject_cl *pRenderHookData = (VisRenderHookDataObject_cl *)pData;
    if (pRenderHookData->m_iEntryConst == VRH_PRE_SCREENMASKS)
    {
      // Debug drawing of all visible touch areas.
#if defined(SUPPORTS_MULTITOUCH)
      if (m_bTouchAreaDebug)
      {
        IVMultiTouchInput* pMultiTouchInput = NULL;
        pMultiTouchInput = static_cast<IVMultiTouchInput*>(&VInputManager::GetInputDevice(INPUT_DEVICE_TOUCHSCREEN));
        VPListT<VTouchArea> touchAreas = pMultiTouchInput->GetTouchAreas();

        const float fBorderWidth = 3.0f;
        VSimpleRenderState_t alphaState(VIS_TRANSP_ALPHA, RENDERSTATEFLAG_FRONTFACE|RENDERSTATEFLAG_NOWIREFRAME|RENDERSTATEFLAG_ALWAYSVISIBLE);

        IVRender2DInterface *pRI = Vision::RenderLoopHelper.BeginOverlayRendering();
        {
          for (int i=0; i<touchAreas.GetLength(); ++i)
          {
            const VRectanglef& rect = touchAreas.Get(i)->GetArea();
            const VColorRef color = touchAreas.Get(i)->GetTouchPointIndex() < 0 ? VColorRef(0, 255, 0, 64) : VColorRef(0, 255, 0, 96);
            pRI->DrawSolidQuad(rect.m_vMin, rect.m_vMax, color, alphaState);

            pRI->DrawSolidQuad(rect.m_vMin, hkvVec2(rect.m_vMax.x, rect.m_vMin.y + fBorderWidth), VColorRef(0, 255, 0, 255), alphaState);
            pRI->DrawSolidQuad(hkvVec2(rect.m_vMin.x, rect.m_vMax.y - fBorderWidth), rect.m_vMax, VColorRef(0, 255, 0, 255), alphaState);
            pRI->DrawSolidQuad(hkvVec2(rect.m_vMin.x, rect.m_vMin.y + fBorderWidth), hkvVec2(rect.m_vMin.x + fBorderWidth, rect.m_vMax.y - fBorderWidth), VColorRef(0, 255, 0, 255), alphaState);
            pRI->DrawSolidQuad(hkvVec2(rect.m_vMax.x - fBorderWidth, rect.m_vMin.y + fBorderWidth), hkvVec2(rect.m_vMax.x, rect.m_vMax.y - fBorderWidth), VColorRef(0, 255, 0, 255), alphaState);
          }
        }
        Vision::RenderLoopHelper.EndOverlayRendering();
      }
#endif
    }
  }

  int iIndex = GetCallbackIndex(pData);
  if (iIndex >= 0)
  {
    if (iIndex == OPTION_FPS)
    {
      m_bFpsVisible = !m_bFpsVisible;
    }
    else if (iIndex == OPTION_WIREFRAME)
    {
      if (Vision::Renderer.GetWireframeMode())
        Vision::Renderer.SetWireframeMode(false);
      else
        Vision::Renderer.SetWireframeMode(true);
    }
    else if (iIndex == OPTION_RELOAD_RESOURCES)
    {
      int iCount = Vision::ResourceSystem.ReloadModifiedResourceFiles(NULL, VURO_HOT_RELOAD);       

      // Clear effect caches so that material shaders will be re-created (not re-used).
      Vision::Shaders.GetShaderFXLibManager().ResetCompiledEffectCaches();

      // Reassign all material shaders.
      Vision::Shaders.ReloadAllShaderAssignmentFiles();

      Vision::Message.Add(1, "%i resources were outdated and have been reloaded.", iCount);
    }
    else if (iIndex == OPTION_TIME_STEP_GRAPH)
    {
      m_pTimeStepGraph->SetVisible(!m_pTimeStepGraph->IsVisible());
    }
#if defined(SUPPORTS_MULTITOUCH)
    else if (iIndex == OPTION_MULTITOUCH)
    {
      m_bTouchAreaDebug = !m_bTouchAreaDebug;
    }
#endif
    else if (iIndex == OPTION_SAVE_SCREENSHOT)
    {
      m_bSaveScreenshot = true;

      // We don't want the menu to be visible in the screenshot
      VAppMenu* pMainMenu = GetParent()->GetAppModule<VAppMenu>();
      if (pMainMenu != NULL)
        pMainMenu->SetVisible(false);
    }
  }

  iIndex = GetCallbackIndex(m_debugInfos, pData);
  if (iIndex >= 0)
    Vision::Profiling.ToggleDebugRenderFlags((unsigned int)iIndex);
}
  // internal helpers:
  static inline int MapTrigger( VStringInputMap *pMap, const char * szTriggerName,
                                VString & sDeviceName, int iControl,
                                const VInputOptions & options, int iOptTriggerIndex /* = -1 */,
                                const VRectanglef & area, float fPrio,
                                bool bNewTouchArea, int iOptionaAxisControl = -1)
  {
    VASSERT_MSG(pMap!=NULL, "No VStringInputMap present for mapping!");

    if(szTriggerName==NULL || szTriggerName[0]==0)
    {
      Vision::Error.Warning("[Lua] MapTrigger: Trigger name is empty, please specify a proper name.");
      return -1;
    }
    
    sDeviceName.ToLower();

    IVInputDevice* pInputDevice = NULL;
#if defined(SUPPORTS_MULTITOUCH)
    // Special case handling for the virtual thumb stick.
    if (sDeviceName == "virtualthumbstick")
    {
      pInputDevice = s_pVirtualThumbStick;
    }
    else
#endif
    {
      pInputDevice = &VInputManager::GetInputDevice(sDeviceName.AsChar());
    }

    if (pInputDevice == NULL || pInputDevice->GetModel() == INPUT_DEVICE_NONE)
    {
      Vision::Error.Warning("[Lua] MapTrigger: Could not find input device '%s' for trigger '%s'.", sDeviceName.AsChar(), szTriggerName);
      return -1;
    }

    //touch area handling
    if (sDeviceName.Search("touch") || sDeviceName.Search("back"))
    {
      IVMultiTouchInput *pTouchDevice = (IVMultiTouchInput *)pInputDevice;

      if(!bNewTouchArea)
      {
        VTouchArea **ppAreas = pTouchDevice->GetTouchAreas().GetPtrs();

        for(int i=0;i<pTouchDevice->GetTouchAreas().GetLength();i++)
        {
          if(ppAreas[i]->GetArea() == area)
          {
            return pMap->MapTrigger(szTriggerName, ppAreas[i], iControl, options, iOptTriggerIndex);
          }
        }
      }

      //we could not find a matching area -or- do not create a new one:
      VTouchArea* pArea = new VTouchArea(*pTouchDevice, area, fPrio);
      return pMap->MapTrigger(szTriggerName, pArea, iControl, options, iOptTriggerIndex);
    }   

    //mapping for non-touch devices
    if (iOptionaAxisControl >= 0)
      return pMap->MapTriggerAxis(szTriggerName, *pInputDevice, iControl, (unsigned int) iOptionaAxisControl, options, iOptTriggerIndex);
    else
      return pMap->MapTrigger(szTriggerName, *pInputDevice, iControl, options, iOptTriggerIndex);
  }