<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date $
Version:   $Revision $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkClaronTrackingDevice.h"
#include "mitkClaronTool.h"
#include "mitkIGTConfig.h"
#include "mitkTimeStamp.h"
#include <itksys/SystemTools.hxx>
#include <iostream>
#include <itkMutexLockHolder.h>

typedef itk::MutexLockHolder<itk::FastMutexLock> MutexLockHolder;

mitk::ClaronTrackingDevice::ClaronTrackingDevice(): mitk::TrackingDevice()
{
  //set the type of this tracking device
  this->m_Type = ClaronMicron;

  this->m_MultiThreader = itk::MultiThreader::New();
  m_ThreadID = 0;

  m_Device = mitk::ClaronInterface::New();
  //############################# standard directories (from cmake) ##################################
  if (m_Device->IsMicronTrackerInstalled())
  {
#ifdef MITK_MICRON_TRACKER_TEMP_DIR
    m_ToolfilesDir = std::string(MITK_MICRON_TRACKER_TEMP_DIR);
#endif
#ifdef MITK_MICRON_TRACKER_CALIBRATION_DIR
    m_CalibrationDir = std::string(MITK_MICRON_TRACKER_CALIBRATION_DIR);
#endif
  }
  else
  {
    m_ToolfilesDir = "Error - No Microntracker installed";
    m_CalibrationDir = "Error - No Microntracker installed";
  }
  //##################################################################################################
  m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir);
}

mitk::ClaronTrackingDevice::~ClaronTrackingDevice()
{
}

mitk::TrackingTool* mitk::ClaronTrackingDevice::AddTool( const char* toolName, const char* fileName )
{
  mitk::ClaronTool::Pointer t = mitk::ClaronTool::New();
  if (t->LoadFile(fileName) == false)
    return NULL;
  t->SetToolName(toolName);
  if (this->InternalAddTool(t) == false)
    return NULL;
  return t.GetPointer();
}

bool mitk::ClaronTrackingDevice::InternalAddTool(ClaronTool::Pointer tool)
{
  m_AllTools.push_back(tool);
  return true;
}

std::vector<mitk::ClaronTool::Pointer> mitk::ClaronTrackingDevice::DetectTools()
{
  std::vector<mitk::ClaronTool::Pointer> returnValue;
  std::vector<claronToolHandle> allHandles = m_Device->GetAllActiveTools();
  for (std::vector<claronToolHandle>::iterator iter = allHandles.begin(); iter != allHandles.end(); ++iter)
  {
    ClaronTool::Pointer newTool = ClaronTool::New();
    newTool->SetToolName(m_Device->GetName(*iter));
    newTool->SetCalibrationName(m_Device->GetName(*iter));
    newTool->SetToolHandle(*iter);
    returnValue.push_back(newTool);
  }
  return returnValue;
}

bool mitk::ClaronTrackingDevice::StartTracking()
{

  //By Alfred: next line because no temp directory is set if MicronTracker is not installed
  if (!m_Device->IsMicronTrackerInstalled())
    return false;
  //##################################################################################

  //be sure that the temp-directory is empty at start: delete all files in the tool files directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());

  //copy all toolfiles into the temp directory
  for (unsigned int i=0; i<m_AllTools.size(); i++)
  {
    itksys::SystemTools::CopyAFile(m_AllTools[i]->GetFile().c_str(), m_ToolfilesDir.c_str());
  }
  this->SetState(Tracking);            // go to mode Tracking
  this->m_StopTrackingMutex->Lock();  // update the local copy of m_StopTracking
  this->m_StopTracking = false;
  this->m_StopTrackingMutex->Unlock();

  //restart the Microntracker, so it will load the new tool files
  m_Device->StopTracking();
  m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir);

  m_TrackingFinishedMutex->Unlock(); // transfer the execution rights to tracking thread

  if (m_Device->StartTracking())
  {
    mitk::TimeStamp::GetInstance()->Start(this);
    m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this);    // start a new thread that executes the TrackTools() method
    return true;
  }
  else
  {
    m_ErrorMessage = "Error while trying to start the device!";
    return false;
  }
}

bool mitk::ClaronTrackingDevice::StopTracking()
{
  Superclass::StopTracking();
  //delete all files in the tool files directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());
  return true;
}

unsigned int mitk::ClaronTrackingDevice::GetToolCount() const
{
  return (unsigned int)this->m_AllTools.size();
}

mitk::TrackingTool* mitk::ClaronTrackingDevice::GetTool(unsigned int toolNumber) const
{
  if ( toolNumber >= this->GetToolCount())
    return NULL;
  else
    return this->m_AllTools[toolNumber];
}

bool mitk::ClaronTrackingDevice::OpenConnection()
{
  bool returnValue;
  //Create the temp directory
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());

  m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir);
  //m_Device = new ClaronInterface(m_CalibrationDir, m_ToolfilesDir);
  returnValue = m_Device->StartTracking();

  if (returnValue)
  {
    this->SetState(Ready);
  }
  else
  {
    //reset everything
    if (m_Device.IsNull())
    {
      m_Device = mitk::ClaronInterface::New();
      m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir);
    }
    m_Device->StopTracking();
    this->SetState(Setup);
    m_ErrorMessage = "Error while trying to open connection to the MicronTracker.";
  }
  return returnValue;
}

bool mitk::ClaronTrackingDevice::CloseConnection()
{
  bool returnValue = true;
  if (this->GetState() == Setup)
    return true;

  returnValue = m_Device->StopTracking();

  //delete the temporary directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());

  this->SetState(Setup);
  return returnValue;
}

mitk::ClaronInterface* mitk::ClaronTrackingDevice::GetDevice()
{
  return m_Device;
}

std::vector<mitk::ClaronTool::Pointer> mitk::ClaronTrackingDevice::GetAllTools()
{
  return this->m_AllTools;
}

void mitk::ClaronTrackingDevice::TrackTools()
{
  try
  {
    /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */
    MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope

    bool localStopTracking;       // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here
    this->m_StopTrackingMutex->Lock();  // update the local copy of m_StopTracking
    localStopTracking = this->m_StopTracking;
    this->m_StopTrackingMutex->Unlock();

    while (this->GetState() == Tracking)
    {
      this->GetDevice()->GrabFrame();

      std::vector<mitk::ClaronTool::Pointer> detectedTools = this->DetectTools();
      std::vector<mitk::ClaronTool::Pointer> allTools = this->GetAllTools();
      std::vector<mitk::ClaronTool::Pointer>::iterator itAllTools;
      for(itAllTools = allTools.begin(); itAllTools != allTools.end(); itAllTools++)
      {
        mitk::ClaronTool::Pointer currentTool = *itAllTools;

        //test if current tool was detected
        std::vector<mitk::ClaronTool::Pointer>::iterator itDetectedTools;
        bool foundTool = false;
        for(itDetectedTools = detectedTools.begin(); itDetectedTools != detectedTools.end(); itDetectedTools++)
        {
          mitk::ClaronTool::Pointer aktuDet = *itDetectedTools;
          std::string tempString(currentTool->GetCalibrationName());
          if (tempString.compare(aktuDet->GetCalibrationName())==0)
          {
            currentTool->SetToolHandle(aktuDet->GetToolHandle());
            foundTool = true;
          }
        }
        if (!foundTool)
        {
          currentTool->SetToolHandle(0);
        }

        if (currentTool->GetToolHandle() != 0)
        {
          currentTool->SetDataValid(true);
          //get tip position of tool:
          std::vector<double> pos_vector = this->GetDevice()->GetTipPosition(currentTool->GetToolHandle());
          //write tip position into tool:
          mitk::Point3D pos;
          pos[0] = pos_vector[0];
          pos[1] = pos_vector[1];
          pos[2] = pos_vector[2];
          currentTool->SetPosition(pos);
          //get tip quaternion of tool
          std::vector<double> quat = this->GetDevice()->GetTipQuaternions(currentTool->GetToolHandle());
          //write tip quaternion into tool
          mitk::Quaternion orientation(quat[1], quat[2], quat[3], quat[0]);
          currentTool->SetOrientation(orientation);
        }
        else
        {
          mitk::Point3D origin;
          origin.Fill(0);
          currentTool->SetPosition(origin);
          currentTool->SetOrientation(mitk::Quaternion(0,0,0,0));
          currentTool->SetDataValid(false);
        }
      }
      /* Update the local copy of m_StopTracking */
      this->m_StopTrackingMutex->Lock();
      localStopTracking = m_StopTracking;
      this->m_StopTrackingMutex->Unlock();
    }
  }
  catch(...)
  {
    this->StopTracking();
    this->SetErrorMessage("Error while trying to track tools. Thread stopped.");
  }
}

bool mitk::ClaronTrackingDevice::IsMicronTrackerInstalled()
{
  return this->m_Device->IsMicronTrackerInstalled();
}

ITK_THREAD_RETURN_TYPE mitk::ClaronTrackingDevice::ThreadStartTracking(void* pInfoStruct)
{
  /* extract this pointer from Thread Info structure */
  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
  if (pInfo == NULL)
  {
    return ITK_THREAD_RETURN_VALUE;
  }
  if (pInfo->UserData == NULL)
  {
    return ITK_THREAD_RETURN_VALUE;
  }
  ClaronTrackingDevice *trackingDevice = (ClaronTrackingDevice*)pInfo->UserData;

  if (trackingDevice != NULL)
    trackingDevice->TrackTools();

  return ITK_THREAD_RETURN_VALUE;
}<commit_msg>FIX (#3836): added missing check for localStopTracking in while-loop of tracking thread function ClaronTrackingDevice::TrackTools()<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date $
Version:   $Revision $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkClaronTrackingDevice.h"
#include "mitkClaronTool.h"
#include "mitkIGTConfig.h"
#include "mitkTimeStamp.h"
#include <itksys/SystemTools.hxx>
#include <iostream>
#include <itkMutexLockHolder.h>

typedef itk::MutexLockHolder<itk::FastMutexLock> MutexLockHolder;

mitk::ClaronTrackingDevice::ClaronTrackingDevice(): mitk::TrackingDevice()
{
  //set the type of this tracking device
  this->m_Type = ClaronMicron;

  this->m_MultiThreader = itk::MultiThreader::New();
  m_ThreadID = 0;

  m_Device = mitk::ClaronInterface::New();
  //############################# standard directories (from cmake) ##################################
  if (m_Device->IsMicronTrackerInstalled())
  {
#ifdef MITK_MICRON_TRACKER_TEMP_DIR
    m_ToolfilesDir = std::string(MITK_MICRON_TRACKER_TEMP_DIR);
#endif
#ifdef MITK_MICRON_TRACKER_CALIBRATION_DIR
    m_CalibrationDir = std::string(MITK_MICRON_TRACKER_CALIBRATION_DIR);
#endif
  }
  else
  {
    m_ToolfilesDir = "Error - No Microntracker installed";
    m_CalibrationDir = "Error - No Microntracker installed";
  }
  //##################################################################################################
  m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir);
}

mitk::ClaronTrackingDevice::~ClaronTrackingDevice()
{
}

mitk::TrackingTool* mitk::ClaronTrackingDevice::AddTool( const char* toolName, const char* fileName )
{
  mitk::ClaronTool::Pointer t = mitk::ClaronTool::New();
  if (t->LoadFile(fileName) == false)
    return NULL;
  t->SetToolName(toolName);
  if (this->InternalAddTool(t) == false)
    return NULL;
  return t.GetPointer();
}

bool mitk::ClaronTrackingDevice::InternalAddTool(ClaronTool::Pointer tool)
{
  m_AllTools.push_back(tool);
  return true;
}

std::vector<mitk::ClaronTool::Pointer> mitk::ClaronTrackingDevice::DetectTools()
{
  std::vector<mitk::ClaronTool::Pointer> returnValue;
  std::vector<claronToolHandle> allHandles = m_Device->GetAllActiveTools();
  for (std::vector<claronToolHandle>::iterator iter = allHandles.begin(); iter != allHandles.end(); ++iter)
  {
    ClaronTool::Pointer newTool = ClaronTool::New();
    newTool->SetToolName(m_Device->GetName(*iter));
    newTool->SetCalibrationName(m_Device->GetName(*iter));
    newTool->SetToolHandle(*iter);
    returnValue.push_back(newTool);
  }
  return returnValue;
}

bool mitk::ClaronTrackingDevice::StartTracking()
{

  //By Alfred: next line because no temp directory is set if MicronTracker is not installed
  if (!m_Device->IsMicronTrackerInstalled())
    return false;
  //##################################################################################

  //be sure that the temp-directory is empty at start: delete all files in the tool files directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());

  //copy all toolfiles into the temp directory
  for (unsigned int i=0; i<m_AllTools.size(); i++)
  {
    itksys::SystemTools::CopyAFile(m_AllTools[i]->GetFile().c_str(), m_ToolfilesDir.c_str());
  }
  this->SetState(Tracking);            // go to mode Tracking
  this->m_StopTrackingMutex->Lock();  // update the local copy of m_StopTracking
  this->m_StopTracking = false;
  this->m_StopTrackingMutex->Unlock();

  //restart the Microntracker, so it will load the new tool files
  m_Device->StopTracking();
  m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir);

  m_TrackingFinishedMutex->Unlock(); // transfer the execution rights to tracking thread

  if (m_Device->StartTracking())
  {
    mitk::TimeStamp::GetInstance()->Start(this);
    m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this);    // start a new thread that executes the TrackTools() method
    return true;
  }
  else
  {
    m_ErrorMessage = "Error while trying to start the device!";
    return false;
  }
}

bool mitk::ClaronTrackingDevice::StopTracking()
{
  Superclass::StopTracking();
  //delete all files in the tool files directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());
  return true;
}

unsigned int mitk::ClaronTrackingDevice::GetToolCount() const
{
  return (unsigned int)this->m_AllTools.size();
}

mitk::TrackingTool* mitk::ClaronTrackingDevice::GetTool(unsigned int toolNumber) const
{
  if ( toolNumber >= this->GetToolCount())
    return NULL;
  else
    return this->m_AllTools[toolNumber];
}

bool mitk::ClaronTrackingDevice::OpenConnection()
{
  bool returnValue;
  //Create the temp directory
  itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str());

  m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir);
  //m_Device = new ClaronInterface(m_CalibrationDir, m_ToolfilesDir);
  returnValue = m_Device->StartTracking();

  if (returnValue)
  {
    this->SetState(Ready);
  }
  else
  {
    //reset everything
    if (m_Device.IsNull())
    {
      m_Device = mitk::ClaronInterface::New();
      m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir);
    }
    m_Device->StopTracking();
    this->SetState(Setup);
    m_ErrorMessage = "Error while trying to open connection to the MicronTracker.";
  }
  return returnValue;
}

bool mitk::ClaronTrackingDevice::CloseConnection()
{
  bool returnValue = true;
  if (this->GetState() == Setup)
    return true;

  returnValue = m_Device->StopTracking();

  //delete the temporary directory
  itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str());

  this->SetState(Setup);
  return returnValue;
}

mitk::ClaronInterface* mitk::ClaronTrackingDevice::GetDevice()
{
  return m_Device;
}

std::vector<mitk::ClaronTool::Pointer> mitk::ClaronTrackingDevice::GetAllTools()
{
  return this->m_AllTools;
}

void mitk::ClaronTrackingDevice::TrackTools()
{
  try
  {
    /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */
    MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope

    bool localStopTracking;       // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here
    this->m_StopTrackingMutex->Lock();  // update the local copy of m_StopTracking
    localStopTracking = this->m_StopTracking;
    this->m_StopTrackingMutex->Unlock();

    while ((this->GetState() == Tracking) && (localStopTracking == false))
    {
      this->GetDevice()->GrabFrame();

      std::vector<mitk::ClaronTool::Pointer> detectedTools = this->DetectTools();
      std::vector<mitk::ClaronTool::Pointer> allTools = this->GetAllTools();
      std::vector<mitk::ClaronTool::Pointer>::iterator itAllTools;
      for(itAllTools = allTools.begin(); itAllTools != allTools.end(); itAllTools++)
      {
        mitk::ClaronTool::Pointer currentTool = *itAllTools;

        //test if current tool was detected
        std::vector<mitk::ClaronTool::Pointer>::iterator itDetectedTools;
        bool foundTool = false;
        for(itDetectedTools = detectedTools.begin(); itDetectedTools != detectedTools.end(); itDetectedTools++)
        {
          mitk::ClaronTool::Pointer aktuDet = *itDetectedTools;
          std::string tempString(currentTool->GetCalibrationName());
          if (tempString.compare(aktuDet->GetCalibrationName())==0)
          {
            currentTool->SetToolHandle(aktuDet->GetToolHandle());
            foundTool = true;
          }
        }
        if (!foundTool)
        {
          currentTool->SetToolHandle(0);
        }

        if (currentTool->GetToolHandle() != 0)
        {
          currentTool->SetDataValid(true);
          //get tip position of tool:
          std::vector<double> pos_vector = this->GetDevice()->GetTipPosition(currentTool->GetToolHandle());
          //write tip position into tool:
          mitk::Point3D pos;
          pos[0] = pos_vector[0];
          pos[1] = pos_vector[1];
          pos[2] = pos_vector[2];
          currentTool->SetPosition(pos);
          //get tip quaternion of tool
          std::vector<double> quat = this->GetDevice()->GetTipQuaternions(currentTool->GetToolHandle());
          //write tip quaternion into tool
          mitk::Quaternion orientation(quat[1], quat[2], quat[3], quat[0]);
          currentTool->SetOrientation(orientation);
        }
        else
        {
          mitk::Point3D origin;
          origin.Fill(0);
          currentTool->SetPosition(origin);
          currentTool->SetOrientation(mitk::Quaternion(0,0,0,0));
          currentTool->SetDataValid(false);
        }
      }
      /* Update the local copy of m_StopTracking */
      this->m_StopTrackingMutex->Lock();
      localStopTracking = m_StopTracking;
      this->m_StopTrackingMutex->Unlock();
    }
  }
  catch(...)
  {
    this->StopTracking();
    this->SetErrorMessage("Error while trying to track tools. Thread stopped.");
  }
}

bool mitk::ClaronTrackingDevice::IsMicronTrackerInstalled()
{
  return this->m_Device->IsMicronTrackerInstalled();
}

ITK_THREAD_RETURN_TYPE mitk::ClaronTrackingDevice::ThreadStartTracking(void* pInfoStruct)
{
  /* extract this pointer from Thread Info structure */
  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
  if (pInfo == NULL)
  {
    return ITK_THREAD_RETURN_VALUE;
  }
  if (pInfo->UserData == NULL)
  {
    return ITK_THREAD_RETURN_VALUE;
  }
  ClaronTrackingDevice *trackingDevice = (ClaronTrackingDevice*)pInfo->UserData;

  if (trackingDevice != NULL)
    trackingDevice->TrackTools();

  return ITK_THREAD_RETURN_VALUE;
}<|endoftext|>


<commit_before>#include "../include-opencv.hpp"
#include "explorer.hpp"
#include <algorithm>
#include <fmo/processing.hpp>
#include <fmo/region.hpp>
#include <limits>
#include <type_traits>

namespace fmo {
    namespace {
        constexpr int BOUNDS_MIN = std::numeric_limits<int16_t>::min();
        constexpr int BOUNDS_MAX = std::numeric_limits<int16_t>::max();
    }

    void ExplorerV2::findObjects() {
        mObjects.clear();

        // sort valid clusters descending by total length
        auto& sortClusters = mCache.sortClusters;
        sortClusters.clear();

        for (auto& cluster : mClusters) {
            if (cluster.isInvalid()) continue;
            sortClusters.emplace_back(cluster.lengthTotal, &cluster);
        }

        std::sort(begin(sortClusters), end(sortClusters),
                  [](auto& l, auto& r) { return l.first > r.first; });

        // find the longest cluster that is considered an object
        for (auto& sortCluster : sortClusters) {
            if (isObject(*sortCluster.second)) {
                mObjects.push_back(sortCluster.second);
                break;
            } else {
                sortCluster.second->setInvalid(Cluster::NOT_AN_OBJECT);
            }
        }
    }

    bool ExplorerV2::isObject(Cluster& cluster) const {
        // find the bounding box enclosing strips present in the difference images
        cluster.bounds1 = findClusterBoundsInDiff(cluster, mLevel.diff1, mLevel.step);
        cluster.bounds2 = findClusterBoundsInDiff(cluster, mLevel.diff2, mLevel.step);

        // condition: both diffs must have *some* strips present
        if (cluster.bounds1.min.x == BOUNDS_MAX || cluster.bounds2.min.x == BOUNDS_MAX)
            return false;

        // force left-to-right direction
        int xMin = cluster.l.pos.x;
        if (cluster.bounds1.min.x != xMin) {
            // force left-to-right by swapping ranges
            std::swap(cluster.bounds1, cluster.bounds2);
        }

        // condition: leftmost strip must be in range1
        if (cluster.bounds1.min.x != xMin) return false;

        // condition: rightmost strip must be in range2
        int xMax = cluster.r.pos.x;
        if (cluster.bounds2.max.x != xMax) return false;

        // condition: range1 must end a significant distance away from rightmost strip
        int minMotion = int(mCfg.minMotion * (xMax - xMin));
        if (xMax - cluster.bounds1.max.x < minMotion) return false;

        // condition: range2 must start a significant distance away from lefmost strip
        if (cluster.bounds2.min.x - xMin < minMotion) return false;

        return true;
    }

    Bounds ExplorerV2::findClusterBoundsInDiff(const Cluster& cluster, const Mat& diff,
                                               int step) const {
        int halfStep = step / 2;
        const uint8_t* data = diff.data();
        int skip = int(diff.skip());
        Bounds result{{BOUNDS_MAX, BOUNDS_MAX}, {BOUNDS_MIN, BOUNDS_MIN}};

        // iterate over all strips in cluster
        int index = cluster.l.strip;
        while (index != Strip::END) {
            auto& strip = mStrips[index];
            int col = (strip.pos.x - halfStep) / step;
            int row = (strip.pos.y - halfStep) / step;
            uint8_t val = *(data + (row * skip + col));

            // if the center of the strip is in the difference image
            if (val != 0) {
                // update bounds
                result.min.x = std::min(result.min.x, int(strip.pos.x));
                result.min.y = std::min(result.min.y, int(strip.pos.y));
                result.max.x = std::max(result.max.x, int(strip.pos.x));
                result.max.y = std::max(result.max.y, int(strip.pos.y));
            }
            index = strip.special;
        }

        return result;
    }

    // auto ExplorerV2::findBounds(const Trajectory& traj) const -> Bounds {
    //     Bounds result;
    //     result.min = {BOUNDS_MAX, BOUNDS_MAX};
    //     result.max = {BOUNDS_MIN, BOUNDS_MIN};
    //
    //     const Component* comp = &mComponents[traj.first];
    //     const Strip* firstStrip = &mStrips[comp->first];
    //     while (true) {
    //         const Strip* strip = &mStrips[comp->first];
    //         while (true) {
    //             result.min.y = std::min(result.min.y, strip->y - strip->halfHeight);
    //             result.max.y = std::max(result.max.y, strip->y + strip->halfHeight);
    //             if (strip->special == Strip::END) break;
    //             strip = &mStrips[strip->special];
    //         }
    //         if (comp->next == Component::NO_COMPONENT) break;
    //         comp = &mComponents[comp->next];
    //     }
    //     const Strip* lastStrip = &mStrips[comp->last];
    //
    //     int halfWidth = mLevel.step / 2;
    //     result.min.x = firstStrip->x - halfWidth;
    //     result.max.x = lastStrip->x + halfWidth;
    //     return result;
    // }

    Bounds ExplorerV2::getObjectBounds() const {
        auto& obj = *mObjects[0];
        return grow(obj.bounds1, obj.bounds2);
    }

    void ExplorerV2::getObjectDetails(ObjectDetails& out) const {
        // find the bounding box enclosing the object
        auto& obj = *mObjects[0];
        out.bounds1 = obj.bounds1;
        out.bounds2 = obj.bounds2;

        // list object pixels
        getObjectPixels(out);
    }

    void fmo::ExplorerV2::getObjectPixels(ObjectDetails& out) const {
        out.points.clear();
        auto& obj = *mObjects[0];
        int step = mLevel.step;
        int halfStep = step / 2;
        int minX = std::max(obj.bounds1.min.x, obj.bounds2.min.x);
        int maxX = std::min(obj.bounds1.max.x, obj.bounds2.max.x);

        // iterate over all strips in cluster
        int index = obj.l.strip;
        while (index != Strip::END) {
            auto& strip = mStrips[index];

            // if the center of the strip is in both bounding boxes
            if (strip.pos.x >= minX && strip.pos.x <= maxX) {
                // put all pixels in the strip as object pixels
                int ye = strip.pos.y + strip.halfHeight;
                int xe = strip.pos.x + halfStep;

                for (int y = strip.pos.y - strip.halfHeight; y < ye; y++) {
                    for (int x = strip.pos.x - halfStep; x < xe; x++) {
                        out.points.push_back({x, y});
                    }
                }
            }

            index = strip.special;
        }
    }
}
<commit_msg>Fix output point set not sorted<commit_after>#include "../include-opencv.hpp"
#include "explorer.hpp"
#include <algorithm>
#include <fmo/processing.hpp>
#include <fmo/region.hpp>
#include <limits>
#include <type_traits>

namespace fmo {
    namespace {
        constexpr int BOUNDS_MIN = std::numeric_limits<int16_t>::min();
        constexpr int BOUNDS_MAX = std::numeric_limits<int16_t>::max();
    }

    void ExplorerV2::findObjects() {
        mObjects.clear();

        // sort valid clusters descending by total length
        auto& sortClusters = mCache.sortClusters;
        sortClusters.clear();

        for (auto& cluster : mClusters) {
            if (cluster.isInvalid()) continue;
            sortClusters.emplace_back(cluster.lengthTotal, &cluster);
        }

        std::sort(begin(sortClusters), end(sortClusters),
                  [](auto& l, auto& r) { return l.first > r.first; });

        // find the longest cluster that is considered an object
        for (auto& sortCluster : sortClusters) {
            if (isObject(*sortCluster.second)) {
                mObjects.push_back(sortCluster.second);
                break;
            } else {
                sortCluster.second->setInvalid(Cluster::NOT_AN_OBJECT);
            }
        }
    }

    bool ExplorerV2::isObject(Cluster& cluster) const {
        // find the bounding box enclosing strips present in the difference images
        cluster.bounds1 = findClusterBoundsInDiff(cluster, mLevel.diff1, mLevel.step);
        cluster.bounds2 = findClusterBoundsInDiff(cluster, mLevel.diff2, mLevel.step);

        // condition: both diffs must have *some* strips present
        if (cluster.bounds1.min.x == BOUNDS_MAX || cluster.bounds2.min.x == BOUNDS_MAX)
            return false;

        // force left-to-right direction
        int xMin = cluster.l.pos.x;
        if (cluster.bounds1.min.x != xMin) {
            // force left-to-right by swapping ranges
            std::swap(cluster.bounds1, cluster.bounds2);
        }

        // condition: leftmost strip must be in range1
        if (cluster.bounds1.min.x != xMin) return false;

        // condition: rightmost strip must be in range2
        int xMax = cluster.r.pos.x;
        if (cluster.bounds2.max.x != xMax) return false;

        // condition: range1 must end a significant distance away from rightmost strip
        int minMotion = int(mCfg.minMotion * (xMax - xMin));
        if (xMax - cluster.bounds1.max.x < minMotion) return false;

        // condition: range2 must start a significant distance away from lefmost strip
        if (cluster.bounds2.min.x - xMin < minMotion) return false;

        return true;
    }

    Bounds ExplorerV2::findClusterBoundsInDiff(const Cluster& cluster, const Mat& diff,
                                               int step) const {
        int halfStep = step / 2;
        const uint8_t* data = diff.data();
        int skip = int(diff.skip());
        Bounds result{{BOUNDS_MAX, BOUNDS_MAX}, {BOUNDS_MIN, BOUNDS_MIN}};

        // iterate over all strips in cluster
        int index = cluster.l.strip;
        while (index != Strip::END) {
            auto& strip = mStrips[index];
            int col = (strip.pos.x - halfStep) / step;
            int row = (strip.pos.y - halfStep) / step;
            uint8_t val = *(data + (row * skip + col));

            // if the center of the strip is in the difference image
            if (val != 0) {
                // update bounds
                result.min.x = std::min(result.min.x, int(strip.pos.x));
                result.min.y = std::min(result.min.y, int(strip.pos.y));
                result.max.x = std::max(result.max.x, int(strip.pos.x));
                result.max.y = std::max(result.max.y, int(strip.pos.y));
            }
            index = strip.special;
        }

        return result;
    }

    // auto ExplorerV2::findBounds(const Trajectory& traj) const -> Bounds {
    //     Bounds result;
    //     result.min = {BOUNDS_MAX, BOUNDS_MAX};
    //     result.max = {BOUNDS_MIN, BOUNDS_MIN};
    //
    //     const Component* comp = &mComponents[traj.first];
    //     const Strip* firstStrip = &mStrips[comp->first];
    //     while (true) {
    //         const Strip* strip = &mStrips[comp->first];
    //         while (true) {
    //             result.min.y = std::min(result.min.y, strip->y - strip->halfHeight);
    //             result.max.y = std::max(result.max.y, strip->y + strip->halfHeight);
    //             if (strip->special == Strip::END) break;
    //             strip = &mStrips[strip->special];
    //         }
    //         if (comp->next == Component::NO_COMPONENT) break;
    //         comp = &mComponents[comp->next];
    //     }
    //     const Strip* lastStrip = &mStrips[comp->last];
    //
    //     int halfWidth = mLevel.step / 2;
    //     result.min.x = firstStrip->x - halfWidth;
    //     result.max.x = lastStrip->x + halfWidth;
    //     return result;
    // }

    Bounds ExplorerV2::getObjectBounds() const {
        auto& obj = *mObjects[0];
        return grow(obj.bounds1, obj.bounds2);
    }

    void ExplorerV2::getObjectDetails(ObjectDetails& out) const {
        // find the bounding box enclosing the object
        auto& obj = *mObjects[0];
        out.bounds1 = obj.bounds1;
        out.bounds2 = obj.bounds2;

        // list object pixels
        getObjectPixels(out);
    }

    void fmo::ExplorerV2::getObjectPixels(ObjectDetails& out) const {
        out.points.clear();
        auto& obj = *mObjects[0];
        int step = mLevel.step;
        int halfStep = step / 2;
        int minX = std::max(obj.bounds1.min.x, obj.bounds2.min.x);
        int maxX = std::min(obj.bounds1.max.x, obj.bounds2.max.x);

        // iterate over all strips in cluster
        int index = obj.l.strip;
        while (index != Strip::END) {
            auto& strip = mStrips[index];

            // if the center of the strip is in both bounding boxes
            if (strip.pos.x >= minX && strip.pos.x <= maxX) {
                // put all pixels in the strip as object pixels
                int ye = strip.pos.y + strip.halfHeight;
                int xe = strip.pos.x + halfStep;

                for (int y = strip.pos.y - strip.halfHeight; y < ye; y++) {
                    for (int x = strip.pos.x - halfStep; x < xe; x++) {
                        out.points.push_back({x, y});
                    }
                }
            }

            index = strip.special;
        }

        // sort to enable fast comparion with other point lists
        std::sort(begin(out.points), end(out.points), pointSetComp);
    }
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESExtSupport.h"
#include "OgreLogManager.h"

namespace Ogre
{
    //-----------------------------------------------------------------------------
	String logObjectInfo(const String& msg, const GLuint obj)
	{
		String logMessage = msg;

		if (obj > 0)
		{
			GLint infologLength = 0;

            if(glIsShader(obj))
            {
                glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }
            else if(glIsProgram(obj))
            {
                glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }

			if (infologLength > 0)
			{
				GLint charsWritten  = 0;

				//GLchar * infoLog = OGRE_NEW GLchar[infologLength];
				char * infoLog = new char [infologLength];

                if(glIsShader(obj))
                {
                    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
                else if(glIsProgram(obj))
                {
                    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
				logMessage += "\n" + String(infoLog);

                LogManager::getSingleton().logMessage(logMessage);

				OGRE_DELETE [] infoLog;
			}
		}

		return logMessage;
	}

} // namespace Ogre
<commit_msg>GLES2 render system: Fixed a possible buffer overflow in logObjectInfo.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESExtSupport.h"
#include "OgreLogManager.h"

namespace Ogre
{
    //-----------------------------------------------------------------------------
	String logObjectInfo(const String& msg, const GLuint obj)
	{
		String logMessage = msg;

		if (obj > 0)
		{
			GLint infologLength = 0;

            if(glIsShader(obj))
            {
                glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }
            else if(glIsProgram(obj))
            {
                glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }

			if (infologLength > 0)
			{
				GLint charsWritten  = 0;

				//GLchar * infoLog = OGRE_NEW GLchar[infologLength];
				char * infoLog = new char [infologLength];
				infoLog[0] = 0;

                if(glIsShader(obj))
                {
                    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
                else if(glIsProgram(obj))
                {
                    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
				if (strlen(infoLog) > 0)
				{
					logMessage += "\n" + String(infoLog);
				}

                LogManager::getSingleton().logMessage(logMessage);

				OGRE_DELETE [] infoLog;
			}
		}

		return logMessage;
	}

} // namespace Ogre
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Facebook, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <folly/io/async/Request.h>

#include <glog/logging.h>

#include <folly/SingletonThreadLocal.h>

namespace folly {

void RequestContext::setContextData(
    const std::string& val,
    std::unique_ptr<RequestData> data) {
  folly::RWSpinLock::WriteHolder guard(lock);
  if (data_.find(val) != data_.end()) {
    LOG_FIRST_N(WARNING, 1)
        << "Called RequestContext::setContextData with data already set";

    data_[val] = nullptr;
  } else {
    data_[val] = std::move(data);
  }
}

bool RequestContext::setContextDataIfAbsent(
    const std::string& val,
    std::unique_ptr<RequestData> data) {
  folly::RWSpinLock::UpgradedHolder guard(lock);
  if (data_.find(val) != data_.end()) {
    return false;
  }

  folly::RWSpinLock::WriteHolder writeGuard(std::move(guard));
  data_[val] = std::move(data);
  return true;
}

bool RequestContext::hasContextData(const std::string& val) const {
  folly::RWSpinLock::ReadHolder guard(lock);
  return data_.find(val) != data_.end();
}

RequestData* RequestContext::getContextData(const std::string& val) {
  folly::RWSpinLock::ReadHolder guard(lock);
  auto r = data_.find(val);
  if (r == data_.end()) {
    return nullptr;
  } else {
    return r->second.get();
  }
}

const RequestData* RequestContext::getContextData(
    const std::string& val) const {
  folly::RWSpinLock::ReadHolder guard(lock);
  auto r = data_.find(val);
  if (r == data_.end()) {
    return nullptr;
  } else {
    return r->second.get();
  }
}

void RequestContext::onSet() {
  folly::RWSpinLock::ReadHolder guard(lock);
  for (auto const& ent : data_) {
    if (RequestData* data = ent.second.get()) {
      data->onSet();
    }
  }
}

void RequestContext::onUnset() {
  folly::RWSpinLock::ReadHolder guard(lock);
  for (auto const& ent : data_) {
    if (RequestData* data = ent.second.get()) {
      data->onUnset();
    }
  }
}

void RequestContext::clearContextData(const std::string& val) {
  folly::RWSpinLock::WriteHolder guard(lock);
  data_.erase(val);
}

std::shared_ptr<RequestContext> RequestContext::setContext(
    std::shared_ptr<RequestContext> ctx) {
  auto& prev = getStaticContext();
  if (ctx != prev) {
    using std::swap;
    if (prev) {
      prev->onUnset();
    }
    if (ctx) {
      ctx->onSet();
    }
    swap(ctx, prev);
  }
  return ctx;
}

std::shared_ptr<RequestContext>& RequestContext::getStaticContext() {
  using SingletonT = SingletonThreadLocal<std::shared_ptr<RequestContext>>;
  static SingletonT singleton;

  return singleton.get();
}
}
<commit_msg>Create trace points for thread events<commit_after>/*
 * Copyright 2016 Facebook, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <folly/io/async/Request.h>

#include <glog/logging.h>

#include <folly/SingletonThreadLocal.h>

namespace folly {

void RequestContext::setContextData(
    const std::string& val,
    std::unique_ptr<RequestData> data) {
  folly::RWSpinLock::WriteHolder guard(lock);
  if (data_.find(val) != data_.end()) {
    LOG_FIRST_N(WARNING, 1)
        << "Called RequestContext::setContextData with data already set";

    data_[val] = nullptr;
  } else {
    data_[val] = std::move(data);
  }
}

bool RequestContext::setContextDataIfAbsent(
    const std::string& val,
    std::unique_ptr<RequestData> data) {
  folly::RWSpinLock::UpgradedHolder guard(lock);
  if (data_.find(val) != data_.end()) {
    return false;
  }

  folly::RWSpinLock::WriteHolder writeGuard(std::move(guard));
  data_[val] = std::move(data);
  return true;
}

bool RequestContext::hasContextData(const std::string& val) const {
  folly::RWSpinLock::ReadHolder guard(lock);
  return data_.find(val) != data_.end();
}

RequestData* RequestContext::getContextData(const std::string& val) {
  folly::RWSpinLock::ReadHolder guard(lock);
  auto r = data_.find(val);
  if (r == data_.end()) {
    return nullptr;
  } else {
    return r->second.get();
  }
}

const RequestData* RequestContext::getContextData(
    const std::string& val) const {
  folly::RWSpinLock::ReadHolder guard(lock);
  auto r = data_.find(val);
  if (r == data_.end()) {
    return nullptr;
  } else {
    return r->second.get();
  }
}

void RequestContext::onSet() {
  folly::RWSpinLock::ReadHolder guard(lock);
  for (auto const& ent : data_) {
    if (RequestData* data = ent.second.get()) {
      data->onSet();
    }
  }
}

void RequestContext::onUnset() {
  folly::RWSpinLock::ReadHolder guard(lock);
  for (auto const& ent : data_) {
    if (RequestData* data = ent.second.get()) {
      data->onUnset();
    }
  }
}

void RequestContext::clearContextData(const std::string& val) {
  folly::RWSpinLock::WriteHolder guard(lock);
  data_.erase(val);
}

std::shared_ptr<RequestContext> RequestContext::setContext(
    std::shared_ptr<RequestContext> ctx) {
  auto& curCtx = getStaticContext();
  if (ctx != curCtx) {
    using std::swap;
    if (curCtx) {
      curCtx->onUnset();
    }
    swap(ctx, curCtx);
    if (curCtx) {
      curCtx->onSet();
    }
  }
  return ctx;
}

std::shared_ptr<RequestContext>& RequestContext::getStaticContext() {
  using SingletonT = SingletonThreadLocal<std::shared_ptr<RequestContext>>;
  static SingletonT singleton;

  return singleton.get();
}
}
<|endoftext|>


<commit_before>#include "emulation.h"
#include "sift_assert.h"
#include "globals.h"
#include "threads.h"

#include <pin.H>

static void handleRdtsc(THREADID threadid, PIN_REGISTER * gax, PIN_REGISTER * gdx)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeRdtsc, req, res);

   if (emulated)
   {
      // Return in eax and edx
      gdx->dword[0] = res.rdtsc.cycles >> 32;
      gax->dword[0] = res.rdtsc.cycles & 0xffffffff;
   }
}

static void handleCpuid(THREADID threadid, PIN_REGISTER * gax, PIN_REGISTER * gbx, PIN_REGISTER * gcx, PIN_REGISTER * gdx)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;

   req.cpuid.eax = gax->dword[0];
   req.cpuid.ecx = gcx->dword[0];
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeCpuid, req, res);

   sift_assert(emulated);
   gax->dword[0] = res.cpuid.eax;
   gbx->dword[0] = res.cpuid.ebx;
   gcx->dword[0] = res.cpuid.ecx;
   gdx->dword[0] = res.cpuid.edx;
}

static ADDRINT emuGetNprocs(THREADID threadid)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetProcInfo, req, res);

   sift_assert(emulated);
   return res.getprocinfo.emunprocs;
}

static ADDRINT emuGetCPU(THREADID threadid)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetProcInfo, req, res);

   sift_assert(emulated);
   return res.getprocinfo.procid;
}

ADDRINT emuClockGettime(THREADID threadid, clockid_t clk_id, struct timespec *tp)
{
   switch(clk_id)
   {
      case CLOCK_REALTIME:
      case CLOCK_MONOTONIC:
         // Return simulated time
         if (tp)
         {
            Sift::EmuRequest req;
            Sift::EmuReply res;
            bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetTime, req, res);

            sift_assert(emulated);
            tp->tv_sec = res.gettime.time_ns / 1000000000;
            tp->tv_nsec = res.gettime.time_ns % 1000000000;
         }
         return 0;
      default:
         // Unknown/non-emulated clock types (such as CLOCK_PROCESS_CPUTIME_ID/CLOCK_THREAD_CPUTIME_ID)
         return clock_gettime(clk_id, tp);
   }
}

ADDRINT emuGettimeofday(THREADID threadid, struct timeval *tv, struct timezone *tz)
{
   //sift_assert(tz == NULL); // gettimeofday() with non-NULL timezone not supported
   sift_assert(tv != NULL); // gettimeofday() called with NULL timeval not supported

   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetTime, req, res);

   sift_assert(emulated);
   tv->tv_sec = res.gettime.time_ns / 1000000000;
   tv->tv_usec = (res.gettime.time_ns / 1000) % 1000000;

   return 0;
}

static void insCallback(INS ins, VOID *v)
{
   if (INS_IsRDTSC(ins))
      INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)handleRdtsc, IARG_THREAD_ID, IARG_REG_REFERENCE, REG_GAX, IARG_REG_REFERENCE, REG_GDX, IARG_END);

   if (INS_Opcode(ins) == XED_ICLASS_CPUID)
   {
      INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)handleCpuid, IARG_THREAD_ID, IARG_REG_REFERENCE, REG_GAX, IARG_REG_REFERENCE, REG_GBX, IARG_REG_REFERENCE, REG_GCX, IARG_REG_REFERENCE, REG_GDX, IARG_END);
      INS_Delete(ins);
   }
}

static void rtnCallback(RTN rtn, VOID *v)
{
   std::string rtn_name = RTN_Name(rtn);

   if (rtn_name == "sched_getcpu")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetCPU), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "get_nprocs" || rtn_name == "__get_nprocs")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetNprocs), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "get_nprocs_conf" || rtn_name == "__get_nprocs_conf")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetNprocs), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "clock_gettime")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuClockGettime), IARG_THREAD_ID,
                           IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END);
   else if (rtn_name.find("gettimeofday") != std::string::npos)
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGettimeofday), IARG_THREAD_ID,
                           IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END);
}

void initEmulation()
{
   if (KnobEmulateSyscalls.Value())
   {
      INS_AddInstrumentFunction(insCallback, 0);
      RTN_AddInstrumentFunction(rtnCallback, 0);
   }
}
<commit_msg>[sift] Make sure time returned by gettimeofday() emulation seems to always increase, even in fast-forward mode when there is no timing model, as some benchmarks wait until they see time advance<commit_after>#include "emulation.h"
#include "sift_assert.h"
#include "globals.h"
#include "threads.h"

#include <pin.H>

static void handleRdtsc(THREADID threadid, PIN_REGISTER * gax, PIN_REGISTER * gdx)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeRdtsc, req, res);

   if (emulated)
   {
      // Return in eax and edx
      gdx->dword[0] = res.rdtsc.cycles >> 32;
      gax->dword[0] = res.rdtsc.cycles & 0xffffffff;
   }
}

static void handleCpuid(THREADID threadid, PIN_REGISTER * gax, PIN_REGISTER * gbx, PIN_REGISTER * gcx, PIN_REGISTER * gdx)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;

   req.cpuid.eax = gax->dword[0];
   req.cpuid.ecx = gcx->dword[0];
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeCpuid, req, res);

   sift_assert(emulated);
   gax->dword[0] = res.cpuid.eax;
   gbx->dword[0] = res.cpuid.ebx;
   gcx->dword[0] = res.cpuid.ecx;
   gdx->dword[0] = res.cpuid.edx;
}

static ADDRINT emuGetNprocs(THREADID threadid)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetProcInfo, req, res);

   sift_assert(emulated);
   return res.getprocinfo.emunprocs;
}

static ADDRINT emuGetCPU(THREADID threadid)
{
   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetProcInfo, req, res);

   sift_assert(emulated);
   return res.getprocinfo.procid;
}

ADDRINT emuClockGettime(THREADID threadid, clockid_t clk_id, struct timespec *tp)
{
   switch(clk_id)
   {
      case CLOCK_REALTIME:
      case CLOCK_MONOTONIC:
         // Return simulated time
         if (tp)
         {
            Sift::EmuRequest req;
            Sift::EmuReply res;
            bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetTime, req, res);

            sift_assert(emulated);
            tp->tv_sec = res.gettime.time_ns / 1000000000;
            tp->tv_nsec = res.gettime.time_ns % 1000000000;
         }
         return 0;
      default:
         // Unknown/non-emulated clock types (such as CLOCK_PROCESS_CPUTIME_ID/CLOCK_THREAD_CPUTIME_ID)
         return clock_gettime(clk_id, tp);
   }
}

ADDRINT emuGettimeofday(THREADID threadid, struct timeval *tv, struct timezone *tz)
{
   //sift_assert(tz == NULL); // gettimeofday() with non-NULL timezone not supported
   sift_assert(tv != NULL); // gettimeofday() called with NULL timeval not supported

   Sift::EmuRequest req;
   Sift::EmuReply res;
   bool emulated = thread_data[threadid].output->Emulate(Sift::EmuTypeGetTime, req, res);
   sift_assert(emulated);

   // Make sure time seems to always increase (even in fast-forward mode when there is no timing model)
   static uint64_t t_last = 0;
   if (t_last >= res.gettime.time_ns)
      res.gettime.time_ns = t_last + 1000;
   t_last = res.gettime.time_ns;

   tv->tv_sec = res.gettime.time_ns / 1000000000;
   tv->tv_usec = (res.gettime.time_ns / 1000) % 1000000;

   return 0;
}

static void insCallback(INS ins, VOID *v)
{
   if (INS_IsRDTSC(ins))
      INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)handleRdtsc, IARG_THREAD_ID, IARG_REG_REFERENCE, REG_GAX, IARG_REG_REFERENCE, REG_GDX, IARG_END);

   if (INS_Opcode(ins) == XED_ICLASS_CPUID)
   {
      INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)handleCpuid, IARG_THREAD_ID, IARG_REG_REFERENCE, REG_GAX, IARG_REG_REFERENCE, REG_GBX, IARG_REG_REFERENCE, REG_GCX, IARG_REG_REFERENCE, REG_GDX, IARG_END);
      INS_Delete(ins);
   }
}

static void rtnCallback(RTN rtn, VOID *v)
{
   std::string rtn_name = RTN_Name(rtn);

   if (rtn_name == "sched_getcpu")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetCPU), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "get_nprocs" || rtn_name == "__get_nprocs")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetNprocs), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "get_nprocs_conf" || rtn_name == "__get_nprocs_conf")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGetNprocs), IARG_THREAD_ID, IARG_END);
   else if (rtn_name == "clock_gettime")
      RTN_ReplaceSignature(rtn, AFUNPTR(emuClockGettime), IARG_THREAD_ID,
                           IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END);
   else if (rtn_name.find("gettimeofday") != std::string::npos)
      RTN_ReplaceSignature(rtn, AFUNPTR(emuGettimeofday), IARG_THREAD_ID,
                           IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END);
}

void initEmulation()
{
   if (KnobEmulateSyscalls.Value())
   {
      INS_AddInstrumentFunction(insCallback, 0);
      RTN_AddInstrumentFunction(rtnCallback, 0);
   }
}
<|endoftext|>


<commit_before>// moon.hxx -- model earth's moon
//
// Written by Durk Talsma. Originally started October 1997, for distribution
// with the FlightGear project. Version 2 was written in August and
// September 1998. This code is based upon algorithms and data kindly
// provided by Mr. Paul Schlyter. (pausch@saaf.se).
//
// Separated out rendering pieces and converted to ssg by Curt Olson,
// March 2000
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/compiler.h>

#include <stdio.h>
#include STL_IOSTREAM

#include <osg/Array>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Node>
#include <osg/ShadeModel>
#include <osg/TexEnv>
#include <osg/Texture2D>

#include <simgear/constants.h>
#include <simgear/screen/colors.hxx>
#include <simgear/scene/model/model.hxx>

#include "sphere.hxx"
#include "moon.hxx"

// Constructor
SGMoon::SGMoon( void ) :
    prev_moon_angle(-1)
{
}

// Destructor
SGMoon::~SGMoon( void ) {
}

// build the moon object
osg::Node*
SGMoon::build( SGPath path, double moon_size ) {

    osg::Node* orb = SGMakeSphere(moon_size, 15, 15);
    osg::StateSet* stateSet = orb->getOrCreateStateSet();
    stateSet->setRenderBinDetails(-5, "RenderBin");

    // set up the orb state
    path.append( "moon.rgba" );

    osg::Texture2D* texture = SGLoadTexture2D(path);
    stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    osg::TexEnv* texEnv = new osg::TexEnv;
    texEnv->setMode(osg::TexEnv::MODULATE);
    stateSet->setTextureAttribute(0, texEnv, osg::StateAttribute::ON);

    orb_material = new osg::Material;
    orb_material->setColorMode(osg::Material::DIFFUSE);
    orb_material->setDiffuse(osg::Material::FRONT_AND_BACK,
                             osg::Vec4(1, 1, 1, 1));
    orb_material->setAmbient(osg::Material::FRONT_AND_BACK,
                             osg::Vec4(0, 0, 0, 1));
    orb_material->setEmission(osg::Material::FRONT_AND_BACK,
                              osg::Vec4(0, 0, 0, 1));
    orb_material->setSpecular(osg::Material::FRONT_AND_BACK,
                              osg::Vec4(0, 0, 0, 1));
    orb_material->setShininess(osg::Material::FRONT_AND_BACK, 0);
    stateSet->setAttribute(orb_material.get());
    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
    osg::ShadeModel* shadeModel = new osg::ShadeModel;
    shadeModel->setMode(osg::ShadeModel::SMOOTH);
    stateSet->setAttributeAndModes(shadeModel);
    osg::CullFace* cullFace = new osg::CullFace;
    cullFace->setMode(osg::CullFace::BACK);
    stateSet->setAttributeAndModes(cullFace);

    osg::BlendFunc* blendFunc = new osg::BlendFunc;
    blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
    stateSet->setAttributeAndModes(blendFunc);

//     osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
//     alphaFunc->setFunction(osg::AlphaFunc::GREATER);
//     alphaFunc->setReferenceValue(0.01);
//     stateSet->setAttributeAndModes(alphaFunc);
    stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);

    // force a repaint of the moon colors with arbitrary defaults
    repaint( 0.0 );

    // build the ssg scene graph sub tree for the sky and connected
    // into the provide scene graph branch
    moon_transform = new osg::MatrixTransform;

    moon_transform->addChild( orb );

    return moon_transform.get();
}

// repaint the moon colors based on current value of moon_angle in
// degrees relative to verticle
// 0 degrees = high noon
// 90 degrees = moon rise/set
// 180 degrees = darkest midnight
bool SGMoon::repaint( double moon_angle ) {

    if (prev_moon_angle == moon_angle)
        return true;

    prev_moon_angle = moon_angle;

    float moon_factor = 4*cos(moon_angle);

    if (moon_factor > 1) moon_factor = 1.0;
    if (moon_factor < -1) moon_factor = -1.0;
    moon_factor = moon_factor/2 + 0.5;

    osg::Vec4 color;
    color[1] = sqrt(moon_factor);
    color[0] = sqrt(color[1]);
    color[2] = moon_factor * moon_factor;
    color[2] *= color[2];
    color[3] = 1.0;

    gamma_correct_rgb( color._v );

    orb_material->setDiffuse(osg::Material::FRONT_AND_BACK, color);

    return true;
}

// reposition the moon at the specified right ascension and
// declination, offset by our current position (p) so that it appears
// fixed at a great distance from the viewer.  Also add in an optional
// rotation (i.e. for the current time of day.)
bool SGMoon::reposition( const SGVec3f& p, double angle,
			 double rightAscension, double declination,
			 double moon_dist )
{
    osg::Matrix T1, T2, GST, RA, DEC;

    T1.makeTranslate(p.osg());

    GST.makeRotate(SGD_DEGREES_TO_RADIANS*angle, osg::Vec3(0, 0, -1));

    // xglRotatef( ((SGD_RADIANS_TO_DEGREES * rightAscension)- 90.0),
    //             0.0, 0.0, 1.0);
    RA.makeRotate(rightAscension - 90.0 * SGD_DEGREES_TO_RADIANS,
                  osg::Vec3(0, 0, 1));

    // xglRotatef((SGD_RADIANS_TO_DEGREES * declination), 1.0, 0.0, 0.0);
    DEC.makeRotate(declination, osg::Vec3(1, 0, 0));

    // xglTranslatef(0,moon_dist);
    T2.makeTranslate(osg::Vec3(0, moon_dist, 0));

    moon_transform->setMatrix(T2*DEC*RA*GST*T1);

    return true;
}

<commit_msg>Modified Files: 	moon.cxx: The moo's state like it was with plib<commit_after>// moon.hxx -- model earth's moon
//
// Written by Durk Talsma. Originally started October 1997, for distribution
// with the FlightGear project. Version 2 was written in August and
// September 1998. This code is based upon algorithms and data kindly
// provided by Mr. Paul Schlyter. (pausch@saaf.se).
//
// Separated out rendering pieces and converted to ssg by Curt Olson,
// March 2000
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/compiler.h>

#include <stdio.h>
#include STL_IOSTREAM

#include <osg/Array>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Node>
#include <osg/ShadeModel>
#include <osg/TexEnv>
#include <osg/Texture2D>

#include <simgear/constants.h>
#include <simgear/screen/colors.hxx>
#include <simgear/scene/model/model.hxx>

#include "sphere.hxx"
#include "moon.hxx"

// Constructor
SGMoon::SGMoon( void ) :
    prev_moon_angle(-1)
{
}

// Destructor
SGMoon::~SGMoon( void ) {
}

// build the moon object
osg::Node*
SGMoon::build( SGPath path, double moon_size ) {

    osg::Node* orb = SGMakeSphere(moon_size, 15, 15);
    osg::StateSet* stateSet = orb->getOrCreateStateSet();
    stateSet->setRenderBinDetails(-5, "RenderBin");

    // set up the orb state
    path.append( "moon.rgba" );

    osg::Texture2D* texture = SGLoadTexture2D(path);
    stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    osg::TexEnv* texEnv = new osg::TexEnv;
    texEnv->setMode(osg::TexEnv::MODULATE);
    stateSet->setTextureAttribute(0, texEnv, osg::StateAttribute::ON);

    orb_material = new osg::Material;
    orb_material->setColorMode(osg::Material::DIFFUSE);
    orb_material->setDiffuse(osg::Material::FRONT_AND_BACK,
                             osg::Vec4(1, 1, 1, 1));
    orb_material->setAmbient(osg::Material::FRONT_AND_BACK,
                             osg::Vec4(0, 0, 0, 1));
    orb_material->setEmission(osg::Material::FRONT_AND_BACK,
                              osg::Vec4(0, 0, 0, 1));
    orb_material->setSpecular(osg::Material::FRONT_AND_BACK,
                              osg::Vec4(0, 0, 0, 1));
    orb_material->setShininess(osg::Material::FRONT_AND_BACK, 0);
    stateSet->setAttribute(orb_material.get());
    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
    osg::ShadeModel* shadeModel = new osg::ShadeModel;
    shadeModel->setMode(osg::ShadeModel::SMOOTH);
    stateSet->setAttributeAndModes(shadeModel);
    osg::CullFace* cullFace = new osg::CullFace;
    cullFace->setMode(osg::CullFace::BACK);
    stateSet->setAttributeAndModes(cullFace);

    osg::BlendFunc* blendFunc = new osg::BlendFunc;
    blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
    stateSet->setAttributeAndModes(blendFunc);

    osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
    alphaFunc->setFunction(osg::AlphaFunc::GREATER);
    alphaFunc->setReferenceValue(0.01);
    stateSet->setAttribute(alphaFunc);
    stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);

    // force a repaint of the moon colors with arbitrary defaults
    repaint( 0.0 );

    // build the ssg scene graph sub tree for the sky and connected
    // into the provide scene graph branch
    moon_transform = new osg::MatrixTransform;

    moon_transform->addChild( orb );

    return moon_transform.get();
}

// repaint the moon colors based on current value of moon_angle in
// degrees relative to verticle
// 0 degrees = high noon
// 90 degrees = moon rise/set
// 180 degrees = darkest midnight
bool SGMoon::repaint( double moon_angle ) {

    if (prev_moon_angle == moon_angle)
        return true;

    prev_moon_angle = moon_angle;

    float moon_factor = 4*cos(moon_angle);

    if (moon_factor > 1) moon_factor = 1.0;
    if (moon_factor < -1) moon_factor = -1.0;
    moon_factor = moon_factor/2 + 0.5;

    osg::Vec4 color;
    color[1] = sqrt(moon_factor);
    color[0] = sqrt(color[1]);
    color[2] = moon_factor * moon_factor;
    color[2] *= color[2];
    color[3] = 1.0;

    gamma_correct_rgb( color._v );

    orb_material->setDiffuse(osg::Material::FRONT_AND_BACK, color);

    return true;
}

// reposition the moon at the specified right ascension and
// declination, offset by our current position (p) so that it appears
// fixed at a great distance from the viewer.  Also add in an optional
// rotation (i.e. for the current time of day.)
bool SGMoon::reposition( const SGVec3f& p, double angle,
			 double rightAscension, double declination,
			 double moon_dist )
{
    osg::Matrix T1, T2, GST, RA, DEC;

    T1.makeTranslate(p.osg());

    GST.makeRotate(SGD_DEGREES_TO_RADIANS*angle, osg::Vec3(0, 0, -1));

    // xglRotatef( ((SGD_RADIANS_TO_DEGREES * rightAscension)- 90.0),
    //             0.0, 0.0, 1.0);
    RA.makeRotate(rightAscension - 90.0 * SGD_DEGREES_TO_RADIANS,
                  osg::Vec3(0, 0, 1));

    // xglRotatef((SGD_RADIANS_TO_DEGREES * declination), 1.0, 0.0, 0.0);
    DEC.makeRotate(declination, osg::Vec3(1, 0, 0));

    // xglTranslatef(0,moon_dist);
    T2.makeTranslate(osg::Vec3(0, moon_dist, 0));

    moon_transform->setMatrix(T2*DEC*RA*GST*T1);

    return true;
}

<|endoftext|>


<commit_before>// sound.cxx -- Sound class implementation
//
// Started by Erik Hofman, February 2002
// (Reuses some code from  fg_fx.cxx created by David Megginson)
//
// Copyright (C) 2002  Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/compiler.h>

#include <string.h>

#include <simgear/debug/logstream.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/math/SGMath.hxx>

#include "xmlsound.hxx"

// static double _snd_lin(double v)   { return v; }
static double _snd_inv(double v)   { return (v == 0) ? 1e99 : 1/v; }
static double _snd_abs(double v)   { return (v >= 0) ? v : -v; }
static double _snd_sqrt(double v)  { return sqrt(fabs(v)); }
static double _snd_log10(double v) { return log10(fabs(v)); }
static double _snd_log(double v)   { return log(fabs(v)); }
// static double _snd_sqr(double v)   { return v*v; }
// static double _snd_pow3(double v)  { return v*v*v; }

static const struct {
	char *name;
	double (*fn)(double);
} __sound_fn[] = {
//	{"lin", _snd_lin},
	{"inv", _snd_inv},
	{"abs", _snd_abs},
	{"sqrt", _snd_sqrt},
	{"log", _snd_log10},
	{"ln", _snd_log},
//	{"sqr", _snd_sqr},
//	{"pow3", _snd_pow3},
	{"", NULL}
};

SGXmlSound::SGXmlSound()
  : _sample(NULL),
    _condition(NULL),
    _active(false),
    _name(""),
    _mode(SGXmlSound::ONCE),
    _prev_value(0),
    _dt_play(0.0),
    _dt_stop(0.0),
    _delay(0.0),
    _stopping(0.0)
{
}

SGXmlSound::~SGXmlSound()
{
    if (_sample)
        _sample->stop();

    delete _condition;

    _volume.clear();
    _pitch.clear();
}

void
SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
                 const string &path)
{

   //
   // set global sound properties
   //

   _name = node->getStringValue("name", "");
   SG_LOG(SG_GENERAL, SG_INFO, "Loading sound information for: " << _name );

   const char *mode_str = node->getStringValue("mode", "");
   if ( !strcmp(mode_str, "looped") ) {
       _mode = SGXmlSound::LOOPED;

   } else if ( !strcmp(mode_str, "in-transit") ) {
       _mode = SGXmlSound::IN_TRANSIT;

   } else {
      _mode = SGXmlSound::ONCE;

      if ( strcmp(mode_str, "") )
         SG_LOG(SG_GENERAL,SG_INFO, "  Unknown sound mode, default to 'once'");
   }

   _property = root->getNode(node->getStringValue("property", ""), true);
   SGPropertyNode *condition = node->getChild("condition");
   if (condition != NULL)
      _condition = sgReadCondition(root, condition);

   if (!_property && !_condition)
      SG_LOG(SG_GENERAL, SG_WARN,
             "  Neither a condition nor a property specified");

   _delay = node->getDoubleValue("delay-sec", 0.0);

   //
   // set volume properties
   //
   unsigned int i;
   float v = 0.0;
   vector<SGPropertyNode_ptr> kids = node->getChildren("volume");
   for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
      _snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false};

      if (strcmp(kids[i]->getStringValue("property"), ""))
         volume.prop = root->getNode(kids[i]->getStringValue("property", ""), true);

      const char *intern_str = kids[i]->getStringValue("internal", "");
      if (!strcmp(intern_str, "dt_play"))
         volume.intern = &_dt_play;
      else if (!strcmp(intern_str, "dt_stop"))
         volume.intern = &_dt_stop;

      if ((volume.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
         if (volume.factor < 0.0) {
            volume.factor = -volume.factor;
            volume.subtract = true;
         }

      const char *type_str = kids[i]->getStringValue("type", "");
      if ( strcmp(type_str, "") ) {

         for (int j=0; __sound_fn[j].fn; j++)
           if ( !strcmp(type_str, __sound_fn[j].name) ) {
               volume.fn = __sound_fn[j].fn;
               break;
            }

         if (!volume.fn)
            SG_LOG(SG_GENERAL,SG_INFO,
                   "  Unknown volume type, default to 'lin'");
      }

      volume.offset = kids[i]->getDoubleValue("offset", 0.0);

      if ((volume.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
         SG_LOG( SG_GENERAL, SG_WARN,
          "Volume minimum value below 0. Forced to 0.");

      volume.max = kids[i]->getDoubleValue("max", 0.0);
      if (volume.max && (volume.max < volume.min) )
         SG_LOG(SG_GENERAL,SG_ALERT,
                "  Volume maximum below minimum. Neglected.");

      _volume.push_back(volume);
      v += volume.offset;

   }

   float reference_dist = node->getDoubleValue("reference-dist", 500.0);
   float max_dist = node->getDoubleValue("max-dist", 3000.0);

   //
   // set pitch properties
   //
   float p = 0.0;
   kids = node->getChildren("pitch");
   for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
      _snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false};

      if (strcmp(kids[i]->getStringValue("property", ""), ""))
         pitch.prop = root->getNode(kids[i]->getStringValue("property", ""), true);

      const char *intern_str = kids[i]->getStringValue("internal", "");
      if (!strcmp(intern_str, "dt_play"))
         pitch.intern = &_dt_play;
      else if (!strcmp(intern_str, "dt_stop"))
         pitch.intern = &_dt_stop;

      if ((pitch.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
         if (pitch.factor < 0.0) {
            pitch.factor = -pitch.factor;
            pitch.subtract = true;
         }

      const char *type_str = kids[i]->getStringValue("type", "");
      if ( strcmp(type_str, "") ) {

         for (int j=0; __sound_fn[j].fn; j++)
            if ( !strcmp(type_str, __sound_fn[j].name) ) {
               pitch.fn = __sound_fn[j].fn;
               break;
            }

         if (!pitch.fn)
            SG_LOG(SG_GENERAL,SG_INFO,
                   "  Unknown pitch type, default to 'lin'");
      }

      pitch.offset = kids[i]->getDoubleValue("offset", 1.0);

      if ((pitch.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
         SG_LOG(SG_GENERAL,SG_WARN,
                "  Pitch minimum value below 0. Forced to 0.");

      pitch.max = kids[i]->getDoubleValue("max", 0.0);
      if (pitch.max && (pitch.max < pitch.min) )
         SG_LOG(SG_GENERAL,SG_ALERT,
                "  Pitch maximum below minimum. Neglected");

      _pitch.push_back(pitch);
      p += pitch.offset;
   }

   //
   // Relative position
   //
   sgVec3 offset_pos;
   sgSetVec3( offset_pos, 0.0, 0.0, 0.0 );
   SGPropertyNode_ptr pos = node->getChild("position");
   if ( pos != NULL ) {
       offset_pos[0] = pos->getDoubleValue("x", 0.0);
       offset_pos[1] = -pos->getDoubleValue("y", 0.0);
       offset_pos[2] = pos->getDoubleValue("z", 0.0);
   }

   //
   // Orientation
   //
   sgVec3 dir;
   float inner, outer, outer_gain;
   sgSetVec3( dir, 0.0, 0.0, 0.0 );
   inner = outer = 360.0;
   outer_gain = 0.0;
   pos = node->getChild("orientation");
   if ( pos != NULL ) {
      dir[0] = pos->getDoubleValue("x", 0.0);
      dir[1] = -pos->getDoubleValue("y", 0.0);
      dir[2] = pos->getDoubleValue("z", 0.0);
      inner = pos->getDoubleValue("inner-angle", 360.0);
      outer = pos->getDoubleValue("outer-angle", 360.0);
      outer_gain = pos->getDoubleValue("outer-gain", 0.0);
   }

   //
   // Initialize the sample
   //
   _mgr = sndmgr;
   if ( (_sample = _mgr->find(_name)) == NULL ) {
       // FIXME: Does it make sense to overwrite a previous entry's
       // configuration just because a new entry has the same name?
       // Note that we can't match on identical "path" because we the
       // new entry could be at a different location with different
       // configuration so we need a new sample which creates a new
       // "alSource".  The semantics of what is going on here seems
       // confused and needs to be thought through more carefully.
        _sample = new SGSoundSample( path.c_str(),
                                    node->getStringValue("path", ""),
                                    false );

       _mgr->add( _sample, _name );
   }

   _sample->set_offset_pos( offset_pos );
   _sample->set_orientation(dir, inner, outer, outer_gain);
   _sample->set_volume(v);
   _sample->set_reference_dist( reference_dist );
   _sample->set_max_dist( max_dist );
   _sample->set_pitch(p);
}

void
SGXmlSound::update (double dt)
{
   double curr_value = 0.0;

   //
   // If the state changes to false, stop playing.
   //
   if (_property)
       curr_value = _property->getDoubleValue();

   if (							// Lisp, anyone?
       (_condition && !_condition->test()) ||
       (!_condition && _property &&
        (
         !curr_value ||
         ( (_mode == SGXmlSound::IN_TRANSIT) && (curr_value == _prev_value) )
         )
        )
       )
   {
       if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
           if (_sample->is_playing()) {
               SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play
                      << " sec: " << _name );

               _sample->stop();
           }

           _active = false;
           _dt_stop += dt;
           _dt_play = 0.0;
       } else {
           _stopping += dt;
       }

       return;
   }

   //
   // mode is ONCE and the sound is still playing?
   //
   if (_active && (_mode == SGXmlSound::ONCE)) {

      if (!_sample->is_playing()) {
         _dt_stop += dt;
         _dt_play = 0.0;
      } else {
         _dt_play += dt;
      }

   } else {

      //
      // Update the playing time, cache the current value and
      // clear the delay timer.
      //
      _dt_play += dt;
      _prev_value = curr_value;
      _stopping = 0.0;
   }

   if (_dt_play < _delay)
      return;

   //
   // Update the volume
   //
   int i;
   int max = _volume.size();
   double volume = 1.0;
   double volume_offset = 0.0;

   for(i = 0; i < max; i++) {
      double v = 1.0;

      if (_volume[i].prop)
         v = _volume[i].prop->getDoubleValue();

      else if (_volume[i].intern)
         v = *_volume[i].intern;

      if (_volume[i].fn)
         v = _volume[i].fn(v);

      v *= _volume[i].factor;

      if (_volume[i].max && (v > _volume[i].max))
         v = _volume[i].max;

      else if (v < _volume[i].min)
         v = _volume[i].min;

      if (_volume[i].subtract)				// Hack!
         volume = _volume[i].offset - v;

      else {
         volume_offset += _volume[i].offset;
         volume *= v;
      }
   }

   //
   // Update the pitch
   //
   max = _pitch.size();
   double pitch = 1.0;
   double pitch_offset = 0.0;

   for(i = 0; i < max; i++) {
      double p = 1.0;

      if (_pitch[i].prop)
         p = _pitch[i].prop->getDoubleValue();

      else if (_pitch[i].intern)
         p = *_pitch[i].intern;

      if (_pitch[i].fn)
         p = _pitch[i].fn(p);

      p *= _pitch[i].factor;

      if (_pitch[i].max && (p > _pitch[i].max))
         p = _pitch[i].max;

      else if (p < _pitch[i].min)
         p = _pitch[i].min;

      if (_pitch[i].subtract)				// Hack!
         pitch = _pitch[i].offset - p;

      else {
         pitch_offset += _pitch[i].offset;
         pitch *= p;
      }
   }

   //
   // Change sample state
   //

   double vol = volume_offset + volume;
   if (vol > 1.0) {
      SG_LOG(SG_GENERAL, SG_WARN, "Sound volume too large for '"
              << _name << "':  " << vol << "  ->  clipping to 1.0");
      vol = 1.0;
   }
   _sample->set_volume(vol);
   _sample->set_pitch( pitch_offset + pitch );

   //
   // Do we need to start playing the sample?
   //
   if (!_active) {

      if (_mode == SGXmlSound::ONCE)
         _sample->play(false);

      else
         _sample->play(true);

      SG_LOG(SG_GENERAL, SG_INFO, "Playing audio after " << _dt_stop
                                   << " sec: " << _name);
      SG_LOG(SG_GENERAL, SG_BULK,
                         "Playing " << ((_mode == ONCE) ? "once" : "looped"));

      _active = true;
      _dt_stop = 0.0;
   }
}
<commit_msg>xmlsound: warning--<commit_after>// sound.cxx -- Sound class implementation
//
// Started by Erik Hofman, February 2002
// (Reuses some code from  fg_fx.cxx created by David Megginson)
//
// Copyright (C) 2002  Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/compiler.h>

#include <string.h>

#include <simgear/debug/logstream.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/math/SGMath.hxx>

#include "xmlsound.hxx"

// static double _snd_lin(double v)   { return v; }
static double _snd_inv(double v)   { return (v == 0) ? 1e99 : 1/v; }
static double _snd_abs(double v)   { return (v >= 0) ? v : -v; }
static double _snd_sqrt(double v)  { return sqrt(fabs(v)); }
static double _snd_log10(double v) { return log10(fabs(v)); }
static double _snd_log(double v)   { return log(fabs(v)); }
// static double _snd_sqr(double v)   { return v*v; }
// static double _snd_pow3(double v)  { return v*v*v; }

static const struct {
	const char *name;
	double (*fn)(double);
} __sound_fn[] = {
//	{"lin", _snd_lin},
	{"inv", _snd_inv},
	{"abs", _snd_abs},
	{"sqrt", _snd_sqrt},
	{"log", _snd_log10},
	{"ln", _snd_log},
//	{"sqr", _snd_sqr},
//	{"pow3", _snd_pow3},
	{"", NULL}
};

SGXmlSound::SGXmlSound()
  : _sample(NULL),
    _condition(NULL),
    _active(false),
    _name(""),
    _mode(SGXmlSound::ONCE),
    _prev_value(0),
    _dt_play(0.0),
    _dt_stop(0.0),
    _delay(0.0),
    _stopping(0.0)
{
}

SGXmlSound::~SGXmlSound()
{
    if (_sample)
        _sample->stop();

    delete _condition;

    _volume.clear();
    _pitch.clear();
}

void
SGXmlSound::init(SGPropertyNode *root, SGPropertyNode *node, SGSoundMgr *sndmgr,
                 const string &path)
{

   //
   // set global sound properties
   //

   _name = node->getStringValue("name", "");
   SG_LOG(SG_GENERAL, SG_INFO, "Loading sound information for: " << _name );

   const char *mode_str = node->getStringValue("mode", "");
   if ( !strcmp(mode_str, "looped") ) {
       _mode = SGXmlSound::LOOPED;

   } else if ( !strcmp(mode_str, "in-transit") ) {
       _mode = SGXmlSound::IN_TRANSIT;

   } else {
      _mode = SGXmlSound::ONCE;

      if ( strcmp(mode_str, "") )
         SG_LOG(SG_GENERAL,SG_INFO, "  Unknown sound mode, default to 'once'");
   }

   _property = root->getNode(node->getStringValue("property", ""), true);
   SGPropertyNode *condition = node->getChild("condition");
   if (condition != NULL)
      _condition = sgReadCondition(root, condition);

   if (!_property && !_condition)
      SG_LOG(SG_GENERAL, SG_WARN,
             "  Neither a condition nor a property specified");

   _delay = node->getDoubleValue("delay-sec", 0.0);

   //
   // set volume properties
   //
   unsigned int i;
   float v = 0.0;
   vector<SGPropertyNode_ptr> kids = node->getChildren("volume");
   for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
      _snd_prop volume = {NULL, NULL, NULL, 1.0, 0.0, 0.0, 0.0, false};

      if (strcmp(kids[i]->getStringValue("property"), ""))
         volume.prop = root->getNode(kids[i]->getStringValue("property", ""), true);

      const char *intern_str = kids[i]->getStringValue("internal", "");
      if (!strcmp(intern_str, "dt_play"))
         volume.intern = &_dt_play;
      else if (!strcmp(intern_str, "dt_stop"))
         volume.intern = &_dt_stop;

      if ((volume.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
         if (volume.factor < 0.0) {
            volume.factor = -volume.factor;
            volume.subtract = true;
         }

      const char *type_str = kids[i]->getStringValue("type", "");
      if ( strcmp(type_str, "") ) {

         for (int j=0; __sound_fn[j].fn; j++)
           if ( !strcmp(type_str, __sound_fn[j].name) ) {
               volume.fn = __sound_fn[j].fn;
               break;
            }

         if (!volume.fn)
            SG_LOG(SG_GENERAL,SG_INFO,
                   "  Unknown volume type, default to 'lin'");
      }

      volume.offset = kids[i]->getDoubleValue("offset", 0.0);

      if ((volume.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
         SG_LOG( SG_GENERAL, SG_WARN,
          "Volume minimum value below 0. Forced to 0.");

      volume.max = kids[i]->getDoubleValue("max", 0.0);
      if (volume.max && (volume.max < volume.min) )
         SG_LOG(SG_GENERAL,SG_ALERT,
                "  Volume maximum below minimum. Neglected.");

      _volume.push_back(volume);
      v += volume.offset;

   }

   float reference_dist = node->getDoubleValue("reference-dist", 500.0);
   float max_dist = node->getDoubleValue("max-dist", 3000.0);

   //
   // set pitch properties
   //
   float p = 0.0;
   kids = node->getChildren("pitch");
   for (i = 0; (i < kids.size()) && (i < SGXmlSound::MAXPROP); i++) {
      _snd_prop pitch = {NULL, NULL, NULL, 1.0, 1.0, 0.0, 0.0, false};

      if (strcmp(kids[i]->getStringValue("property", ""), ""))
         pitch.prop = root->getNode(kids[i]->getStringValue("property", ""), true);

      const char *intern_str = kids[i]->getStringValue("internal", "");
      if (!strcmp(intern_str, "dt_play"))
         pitch.intern = &_dt_play;
      else if (!strcmp(intern_str, "dt_stop"))
         pitch.intern = &_dt_stop;

      if ((pitch.factor = kids[i]->getDoubleValue("factor", 1.0)) != 0.0)
         if (pitch.factor < 0.0) {
            pitch.factor = -pitch.factor;
            pitch.subtract = true;
         }

      const char *type_str = kids[i]->getStringValue("type", "");
      if ( strcmp(type_str, "") ) {

         for (int j=0; __sound_fn[j].fn; j++)
            if ( !strcmp(type_str, __sound_fn[j].name) ) {
               pitch.fn = __sound_fn[j].fn;
               break;
            }

         if (!pitch.fn)
            SG_LOG(SG_GENERAL,SG_INFO,
                   "  Unknown pitch type, default to 'lin'");
      }

      pitch.offset = kids[i]->getDoubleValue("offset", 1.0);

      if ((pitch.min = kids[i]->getDoubleValue("min", 0.0)) < 0.0)
         SG_LOG(SG_GENERAL,SG_WARN,
                "  Pitch minimum value below 0. Forced to 0.");

      pitch.max = kids[i]->getDoubleValue("max", 0.0);
      if (pitch.max && (pitch.max < pitch.min) )
         SG_LOG(SG_GENERAL,SG_ALERT,
                "  Pitch maximum below minimum. Neglected");

      _pitch.push_back(pitch);
      p += pitch.offset;
   }

   //
   // Relative position
   //
   sgVec3 offset_pos;
   sgSetVec3( offset_pos, 0.0, 0.0, 0.0 );
   SGPropertyNode_ptr pos = node->getChild("position");
   if ( pos != NULL ) {
       offset_pos[0] = pos->getDoubleValue("x", 0.0);
       offset_pos[1] = -pos->getDoubleValue("y", 0.0);
       offset_pos[2] = pos->getDoubleValue("z", 0.0);
   }

   //
   // Orientation
   //
   sgVec3 dir;
   float inner, outer, outer_gain;
   sgSetVec3( dir, 0.0, 0.0, 0.0 );
   inner = outer = 360.0;
   outer_gain = 0.0;
   pos = node->getChild("orientation");
   if ( pos != NULL ) {
      dir[0] = pos->getDoubleValue("x", 0.0);
      dir[1] = -pos->getDoubleValue("y", 0.0);
      dir[2] = pos->getDoubleValue("z", 0.0);
      inner = pos->getDoubleValue("inner-angle", 360.0);
      outer = pos->getDoubleValue("outer-angle", 360.0);
      outer_gain = pos->getDoubleValue("outer-gain", 0.0);
   }

   //
   // Initialize the sample
   //
   _mgr = sndmgr;
   if ( (_sample = _mgr->find(_name)) == NULL ) {
       // FIXME: Does it make sense to overwrite a previous entry's
       // configuration just because a new entry has the same name?
       // Note that we can't match on identical "path" because we the
       // new entry could be at a different location with different
       // configuration so we need a new sample which creates a new
       // "alSource".  The semantics of what is going on here seems
       // confused and needs to be thought through more carefully.
        _sample = new SGSoundSample( path.c_str(),
                                    node->getStringValue("path", ""),
                                    false );

       _mgr->add( _sample, _name );
   }

   _sample->set_offset_pos( offset_pos );
   _sample->set_orientation(dir, inner, outer, outer_gain);
   _sample->set_volume(v);
   _sample->set_reference_dist( reference_dist );
   _sample->set_max_dist( max_dist );
   _sample->set_pitch(p);
}

void
SGXmlSound::update (double dt)
{
   double curr_value = 0.0;

   //
   // If the state changes to false, stop playing.
   //
   if (_property)
       curr_value = _property->getDoubleValue();

   if (							// Lisp, anyone?
       (_condition && !_condition->test()) ||
       (!_condition && _property &&
        (
         !curr_value ||
         ( (_mode == SGXmlSound::IN_TRANSIT) && (curr_value == _prev_value) )
         )
        )
       )
   {
       if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME)) {
           if (_sample->is_playing()) {
               SG_LOG(SG_GENERAL, SG_INFO, "Stopping audio after " << _dt_play
                      << " sec: " << _name );

               _sample->stop();
           }

           _active = false;
           _dt_stop += dt;
           _dt_play = 0.0;
       } else {
           _stopping += dt;
       }

       return;
   }

   //
   // mode is ONCE and the sound is still playing?
   //
   if (_active && (_mode == SGXmlSound::ONCE)) {

      if (!_sample->is_playing()) {
         _dt_stop += dt;
         _dt_play = 0.0;
      } else {
         _dt_play += dt;
      }

   } else {

      //
      // Update the playing time, cache the current value and
      // clear the delay timer.
      //
      _dt_play += dt;
      _prev_value = curr_value;
      _stopping = 0.0;
   }

   if (_dt_play < _delay)
      return;

   //
   // Update the volume
   //
   int i;
   int max = _volume.size();
   double volume = 1.0;
   double volume_offset = 0.0;

   for(i = 0; i < max; i++) {
      double v = 1.0;

      if (_volume[i].prop)
         v = _volume[i].prop->getDoubleValue();

      else if (_volume[i].intern)
         v = *_volume[i].intern;

      if (_volume[i].fn)
         v = _volume[i].fn(v);

      v *= _volume[i].factor;

      if (_volume[i].max && (v > _volume[i].max))
         v = _volume[i].max;

      else if (v < _volume[i].min)
         v = _volume[i].min;

      if (_volume[i].subtract)				// Hack!
         volume = _volume[i].offset - v;

      else {
         volume_offset += _volume[i].offset;
         volume *= v;
      }
   }

   //
   // Update the pitch
   //
   max = _pitch.size();
   double pitch = 1.0;
   double pitch_offset = 0.0;

   for(i = 0; i < max; i++) {
      double p = 1.0;

      if (_pitch[i].prop)
         p = _pitch[i].prop->getDoubleValue();

      else if (_pitch[i].intern)
         p = *_pitch[i].intern;

      if (_pitch[i].fn)
         p = _pitch[i].fn(p);

      p *= _pitch[i].factor;

      if (_pitch[i].max && (p > _pitch[i].max))
         p = _pitch[i].max;

      else if (p < _pitch[i].min)
         p = _pitch[i].min;

      if (_pitch[i].subtract)				// Hack!
         pitch = _pitch[i].offset - p;

      else {
         pitch_offset += _pitch[i].offset;
         pitch *= p;
      }
   }

   //
   // Change sample state
   //

   double vol = volume_offset + volume;
   if (vol > 1.0) {
      SG_LOG(SG_GENERAL, SG_WARN, "Sound volume too large for '"
              << _name << "':  " << vol << "  ->  clipping to 1.0");
      vol = 1.0;
   }
   _sample->set_volume(vol);
   _sample->set_pitch( pitch_offset + pitch );

   //
   // Do we need to start playing the sample?
   //
   if (!_active) {

      if (_mode == SGXmlSound::ONCE)
         _sample->play(false);

      else
         _sample->play(true);

      SG_LOG(SG_GENERAL, SG_INFO, "Playing audio after " << _dt_stop
                                   << " sec: " << _name);
      SG_LOG(SG_GENERAL, SG_BULK,
                         "Playing " << ((_mode == ONCE) ? "once" : "looped"));

      _active = true;
      _dt_stop = 0.0;
   }
}
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * Project:  integrating laszip into liblas - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2010, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  bytestreamin_istream.hpp

  CONTENTS:

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2010  martin isenburg@cs.unc.edu

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-;

===============================================================================
*/
#ifndef BYTE_STREAM_IN_ISTREAM_H
#define BYTE_STREAM_IN_ISTREAM_H

#include "bytestreamin.hpp"

#if _MSC_VER < 1300
#include <istream.h>
#else
#include <fstream>
#endif

class ByteStreamInIstream : public ByteStreamIn
{
public:
  ByteStreamInIstream(std::istream* stream);
/* read a single byte                                        */
  unsigned int getByte();
/* read an array of bytes                                    */
  bool getBytes(unsigned char* bytes, unsigned int num_bytes);
/* destructor                                                */
  ~ByteStreamInIstream(){};
private:
  std::istream* stream;
  std::ios::off_type start;
};

inline ByteStreamInIstream::ByteStreamInIstream(std::istream* stream)
{
  this->stream = stream;
  resetCount();
}

inline unsigned int ByteStreamInIstream::getByte()
{
  int byte = stream->get();
  if (stream->bad())
  {
    byte = 0;
  }
  return (unsigned int)byte;
}

inline bool ByteStreamInIstream::getBytes(unsigned char* bytes, unsigned int num_bytes)
{
    // http://stackoverflow.com/questions/604431/c-reading-unsigned-char-from-file-stream
    // std::ifstream only provides a specialization for char, not unsigned char.

    // WARNING, unsafe cast!!! -- hobu

  stream->read( (char*)bytes, num_bytes);
  return !!(stream->good());
}

unsigned int ByteStreamInIstream::byteCount() const
{
  std::ios::pos_type end = stream->tellg();
  std::ios::off_type size = end - start;
  return static_cast<unsigned int>(size);
}

void ByteStreamInIstream::resetCount()
{
  start = stream->tellg();
}

#endif
<commit_msg>getting byte count<commit_after>/******************************************************************************
 *
 * Project:  integrating laszip into liblas - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2010, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  bytestreamin_istream.hpp

  CONTENTS:

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2010  martin isenburg@cs.unc.edu

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    12 December 2010 -- created from ByteStreamOutFile after Howard got pushy (-;

===============================================================================
*/
#ifndef BYTE_STREAM_IN_ISTREAM_H
#define BYTE_STREAM_IN_ISTREAM_H

#include "bytestreamin.hpp"

#if _MSC_VER < 1300
#include <istream.h>
#else
#include <fstream>
#endif

class ByteStreamInIstream : public ByteStreamIn
{
public:
  ByteStreamInIstream(std::istream* stream);
/* read a single byte                                        */
  unsigned int getByte();
/* read an array of bytes                                    */
  bool getBytes(unsigned char* bytes, unsigned int num_bytes);
/* returns how many bytes were read since last reset         */
  unsigned int byteCount() const;
/* reset byte counter                                        */
  void resetCount();
/* destructor                                                */
  ~ByteStreamInIstream(){};
private:
  std::istream* stream;
  std::ios::off_type start;
};

inline ByteStreamInIstream::ByteStreamInIstream(std::istream* stream)
{
  this->stream = stream;
  resetCount();
}

inline unsigned int ByteStreamInIstream::getByte()
{
  int byte = stream->get();
  if (stream->bad())
  {
    byte = 0;
  }
  return (unsigned int)byte;
}

inline bool ByteStreamInIstream::getBytes(unsigned char* bytes, unsigned int num_bytes)
{
    // http://stackoverflow.com/questions/604431/c-reading-unsigned-char-from-file-stream
    // std::ifstream only provides a specialization for char, not unsigned char.

    // WARNING, unsafe cast!!! -- hobu

  stream->read( (char*)bytes, num_bytes);
  return !!(stream->good());
}

unsigned int ByteStreamInIstream::byteCount() const
{
  std::ios::pos_type end = stream->tellg();
  std::ios::off_type size = end - start;
  return static_cast<unsigned int>(size);
}

void ByteStreamInIstream::resetCount()
{
  start = stream->tellg();
}

#endif
<|endoftext|>