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

  Program:   Visualization Toolkit
  Module:    vtkSortFileNames.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkSortFileNames.h"

#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"

#include <vtkstd/string>
#include <vtkstd/vector>
#include <vtkstd/list>
#include <vtkstd/algorithm>
#include <vtksys/SystemTools.hxx>

#include <ctype.h>

vtkStandardNewMacro(vtkSortFileNames);

// a container for holding string arrays

class vtkStringArrayVector
{
public:
  typedef vtkstd::vector<vtkSmartPointer<vtkStringArray> > VectorType;

  static vtkStringArrayVector *New() {
    return new vtkStringArrayVector; };

  void Delete() {
    delete this; };

  void Reset() {
    this->Container.clear(); };

  void InsertNextStringArray(vtkStringArray *stringArray) {
    this->Container.push_back(stringArray); };

  vtkStringArray *GetStringArray(int i) {
    return this->Container[static_cast<VectorType::size_type>(i)]; };

  int GetNumberOfStringArrays() {
    return static_cast<int>(this->Container.size()); };

private:
  vtkStringArrayVector() : Container() {};
  ~vtkStringArrayVector() { this->Container.clear(); };

  VectorType Container;
};

//----------------------------------------------------------------------------
vtkSortFileNames::vtkSortFileNames()
{
  this->InputFileNames = 0;
  this->NumericSort = 0;
  this->IgnoreCase = 0;
  this->Grouping = 0;
  this->SkipDirectories = 0;
  this->FileNames = vtkStringArray::New();
  this->Groups = vtkStringArrayVector::New();
}

vtkSortFileNames::~vtkSortFileNames()
{
  if (this->InputFileNames)
    {
    this->InputFileNames->Delete();
    this->InputFileNames = 0;
    }
  if (this->FileNames)
    {
    this->FileNames->Delete();
    this->FileNames = 0;
    }
  if (this->Groups)
    {
    this->Groups->Delete();
    this->Groups = 0;
    }
}

void vtkSortFileNames::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "InputFileNames:  (" << this->GetInputFileNames() << ")\n";
  os << indent << "NumericSort:  " <<
    (this->GetNumericSort() ? "On\n" : "Off\n");
  os << indent << "IgnoreCase:  " <<
    (this->GetIgnoreCase() ? "On\n" : "Off\n");
  os << indent << "Grouping:  " <<
    (this->GetGrouping() ? "On\n" : "Off\n");
  os << indent << "SkipDirectories:  " <<
    (this->GetSkipDirectories() ? "On\n" : "Off\n");

  os << indent << "NumberOfGroups: " << this->GetNumberOfGroups() << "\n";

  if (this->GetGrouping())
    {
    for (int i = 0; i < this->GetNumberOfGroups(); i++)
      {
      os << indent.GetNextIndent() << "Group[" << i << "]:  (" <<
        this->GetNthGroup(i) << ")\n";
      }
    }
  else
    {
    os << indent.GetNextIndent() << "FileNames:  ("
       << this->GetFileNames() << ")\n";
    }
}

void vtkSortFileNames::SetInputFileNames(vtkStringArray *input)
{
  vtkSetObjectBodyMacro(InputFileNames, vtkStringArray, input);
}

int vtkSortFileNames::GetNumberOfGroups()
{
  this->Update();

  return this->Groups->GetNumberOfStringArrays();
}

vtkStringArray *vtkSortFileNames::GetNthGroup(int i)
{
  this->Update();

  if (!this->GetGrouping())
    {
    vtkErrorMacro(<< "GetNthGroup(): Grouping not on.");
    return 0;
    }

  int n = this->Groups->GetNumberOfStringArrays();

  if (i >= 0 && i < n)
    {
    return this->Groups->GetStringArray(i);
    }
  else
    {
    vtkErrorMacro(<< "GetNthGroup(i): index " << i << " is out of range");
    return 0;
    }
}

vtkStringArray *vtkSortFileNames::GetFileNames()
{
  this->Update();

  return this->FileNames;
}

void vtkSortFileNames::GroupFileNames(vtkStringArray *input,
                                      vtkStringArrayVector *output)
{
  vtkstd::string baseName;
  vtkstd::string extension;
  vtkstd::string fileNamePath;
  vtkstd::string reducedName;

  vtkstd::list<unsigned int> ungroupedFiles;
  vtkstd::vector<vtkstd::string> reducedFileNames;

  unsigned int numberOfStrings = input->GetNumberOfValues();
  for (unsigned int i = 0; i < numberOfStrings; i++)
    {
    vtkstd::string& fileName = input->GetValue(i);
    extension = vtksys::SystemTools::GetFilenameLastExtension(fileName);
    fileNamePath = vtksys::SystemTools::GetFilenamePath(fileName);
    baseName = vtksys::SystemTools::GetFilenameWithoutLastExtension(fileName);

    // If extension is all digits, it is not a true extension, so
    // add it back onto the filename.  Note that the extension
    // includes the leading dot.
    int numericExtension = 1;
    for (unsigned int j = 1; j < extension.length(); j++)
      {
      if (!(extension[j] >= '0' && extension[j] <= '9'))
        {
        numericExtension = 0;
        }
      }
    if (numericExtension && extension.length() != 0)
      {
      baseName.append(extension);
      extension = "";
      }

    // Create a reduced filename that replaces all digit sequences
    // in the filename with a single digit "0". We begin by setting
    // the reduced filename to the path.
    reducedName = fileNamePath + "/";
    int inDigitBlock = 0;
    unsigned int charBlockStart = 0;
    unsigned int stringLength = static_cast<unsigned int>(baseName.length());
    for (unsigned int k = 0; k < stringLength; k++)
      {
      if (baseName[k] >= '0' && baseName[k] <= '9')
        {
        if (!inDigitBlock && k != 0)
          {
          reducedName.append(baseName.substr(charBlockStart,
                                             k-charBlockStart));
          reducedName.append("0");
          }
        inDigitBlock = 1;
        }
      else
        {
        if (inDigitBlock)
          {
          charBlockStart = k;
          inDigitBlock = 0;
          }
        }
      }
    if (!inDigitBlock)
      {
      reducedName.append(baseName.substr(charBlockStart,
                                         stringLength-charBlockStart));
      }

    // Add extension back to the filename.
    reducedName.append(extension);

    // If IgnoreCase is set, change to uppercase.
    if (this->IgnoreCase)
      {
      unsigned int n = static_cast<unsigned int>(reducedName.length());
      for (unsigned int j = 0; j < n; j++)
        {
        reducedName[j] = toupper(reducedName[j]);
        }
      }

    // The reduced filename has each block of digits replaced with "0".
    reducedFileNames.push_back(reducedName);

    // push the index onto the "ungrouped" list
    ungroupedFiles.push_back(i);
    }

  // now loop through all files and find all matches
  while (!ungroupedFiles.empty())
    {
    // get the first element in the list
    unsigned int fileIndex = ungroupedFiles.front();
    vtkstd::string& reducedFileName = reducedFileNames[fileIndex];

    vtkStringArray *newGroup = vtkStringArray::New();

    // find all matches and move them into the group
    vtkstd::list<unsigned int>::iterator p = ungroupedFiles.begin();
    while (p != ungroupedFiles.end())
      {
      unsigned int tryIndex = *p;

      if (reducedFileName == reducedFileNames[tryIndex])
        {
        newGroup->InsertNextValue(input->GetValue(tryIndex));
        p = ungroupedFiles.erase(p);
        }
      else
        {
        p++;
        }
      }

    // add the group to the output
    output->InsertNextStringArray(newGroup);
    newGroup->Delete();
    }
}

// Sort filenames lexicographically, ignoring case.
bool vtkCompareFileNamesIgnoreCase(const vtkstd::string s1,
                                   const vtkstd::string s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // find the minimum of the two lengths
  unsigned int n = n1;
  if (n > n2)
    {
    n = n2;
    }

  // compare the strings with no case
  for (unsigned int i = 0; i < n; i++)
    {
    char c1 = toupper(s1[i]);
    char c2 = toupper(s2[i]);

    if (c1 < c2)
      {
      return 1;
      }
    if (c1 > c2)
      {
      return 0;
      }
    }

  // if it is a tie, then the short string is "less"
  if (n1 < n2)
    {
    return 1;
    }

  // if strings are equal, use case-sensitive comparison to break tie
  if (n1 == n2)
    {
    return (s1 < s2);
    }

  // otherwise, if n1 > n2, then n1 wins
  return 0;
}

// Sort filenames numerically
bool vtkCompareFileNamesNumeric(const vtkstd::string s1,
                                const vtkstd::string s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // compare the strings numerically
  unsigned int i1 = 0;
  unsigned int i2 = 0;
  while (i1 < n1 && i2 < n2)
    {
    char c1 = s1[i1++];
    char c2 = s2[i2++];

    if (0 && (c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
      {
      // convert decimal numeric sequence into an integer
      unsigned int j1 = 0;
      while (c1 >= '0' && c1 <= '9')
        {
        j1 = (j1 << 3) + (j1 << 1) + (c1 - '0');
        if (i1 == n1)
          {
          break;
          }
        c1 = s1[i1++];
        }

      // convert decimal numeric sequence into an integer
      unsigned int j2 = 0;
      while (c2 >= '0' && c2 <= '9')
        {
        j2 = (j2 << 3) + (j2 << 1) + (c2 - '0');
        if (i2 == n2)
          {
          break;
          }
        c2 = s2[i2++];
        }

      // perform the numeric comparison
      if (j1 < j2)
        {
        return 1;
        }
      if (j1 > j2)
        {
        return 0;
        }
      }

    // case-insensitive lexicographic comparison of non-digits
    if ((c1 < '0' || c1 > '9') || (c2 < '0' || c2 > '9'))
      {
      if (c1 < c2)
        {
        return 1;
        }
      if (c1 > c2)
        {
        return 0;
        }
      }
    }

  // if it is a tie, then the shorter string is "less"
  if ((n1 - i1) < (n2 - i2))
    {
    return 1;
    }

  // if strings are otherwise equal, fall back to default to break tie
  if ((i1 == n1) && (i2 == n2))
    {
    return (s1 < s2);
    }

  // otherwise, return false
  return 0;
}

// Sort filenames numerically
bool vtkCompareFileNamesNumericIgnoreCase(const vtkstd::string s1,
                                          const vtkstd::string s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // compare the strings numerically
  unsigned int i1 = 0;
  unsigned int i2 = 0;
  while (i1 < n1 && i2 < n2)
    {
    char c1 = s1[i1++];
    char c2 = s2[i2++];

    if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
      {
      // convert decimal numeric sequence into an integer
      unsigned int j1 = 0;
      while (c1 >= '0' && c1 <= '9')
        {
        j1 = (j1 << 3) + (j1 << 1) + (c1 - '0');
        if (i1 == n1)
          {
          break;
          }
        c1 = s1[i1++];
        }

      // convert decimal numeric sequence into an integer
      unsigned int j2 = 0;
      while (c2 >= '0' && c2 <= '9')
        {
        j2 = (j2 << 3) + (j2 << 1) + (c2 - '0');
        if (i2 == n2)
          {
          break;
          }
        c2 = s2[i2++];
        }

      // perform the numeric comparison
      if (j1 < j2)
        {
        return 1;
        }
      if (j1 > j2)
        {
        return 0;
        }
      }

    // case-insensitive lexicographic comparison of non-digits
    if ((c1 < '0' || c1 > '9') || (c2 < '0' || c2 > '9'))
      {
      c1 = toupper(c1);
      c2 = toupper(c2);

      if (c1 < c2)
        {
        return 1;
        }
      if (c1 > c2)
        {
        return 0;
        }
      }
    }

  // if it is a tie, then the shorter string is "less"
  if ((n1 - i1) < (n2 - i2))
    {
    return 1;
    }

  // if strings are otherwise equal, fall back to default to break tie
  if ((i1 == n1) && (i2 == n2))
    {
    return vtkCompareFileNamesIgnoreCase(s1, s2);
    }

  // otherwise, return false
  return 0;
}

void vtkSortFileNames::SortFileNames(vtkStringArray *input,
                                     vtkStringArray *output)
{
  // convert vtkStringArray into an STL vector
  vtkstd::vector<vtkstd::string> fileNames;
  unsigned int numberOfStrings = input->GetNumberOfValues();
  for (unsigned int j = 0; j < numberOfStrings; j++)
    {
    vtkstd::string& fileName = input->GetValue(j);

    // skip anything that is a directory
    if (this->SkipDirectories &&
        vtksys::SystemTools::FileIsDirectory(fileName.c_str()))
      {
      continue;
      }

    // build a new list
    fileNames.push_back(fileName);
    }

  // perform the sort according to the options that are set
  if (this->IgnoreCase)
    {
    if (this->NumericSort)
      {
      // numeric sort without case sensitivity
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesNumericIgnoreCase);
      }
    else
      {
      // lexicographic sort without case sensitivity
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesIgnoreCase);
      }
    }
  else
    {
    if (this->NumericSort)
      {
      // numeric sort
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesNumeric);
      }
    else
      {
      // lexicographic sort (the default)
      vtkstd::sort(fileNames.begin(), fileNames.end());
      }
    }

  // build the output
  vtkstd::vector<vtkstd::string>::iterator iter = fileNames.begin();
  while (iter < fileNames.end())
    {
    output->InsertNextValue(*iter++);
    }
}

void vtkSortFileNames::Execute()
{
  // sort the input file names
  this->FileNames->Reset();
  this->SortFileNames(this->InputFileNames, this->FileNames);

  // group the sorted files if grouping is on
  this->Groups->Reset();
  if (this->Grouping)
    {
    this->GroupFileNames(this->FileNames, this->Groups);
    }
}

void vtkSortFileNames::Update()
{
  if (this->InputFileNames != 0)
    {
    if (this->GetMTime() > this->UpdateTime.GetMTime() ||
        this->InputFileNames->GetMTime() > this->UpdateTime.GetMTime())
      {
      this->Execute();
      this->UpdateTime.Modified();
      }
    }
}
<commit_msg>ENH: Pass strings to comparison function by reference.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSortFileNames.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkSortFileNames.h"

#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"

#include <vtkstd/string>
#include <vtkstd/vector>
#include <vtkstd/list>
#include <vtkstd/algorithm>
#include <vtksys/SystemTools.hxx>

#include <ctype.h>

vtkStandardNewMacro(vtkSortFileNames);

// a container for holding string arrays

class vtkStringArrayVector
{
public:
  typedef vtkstd::vector<vtkSmartPointer<vtkStringArray> > VectorType;

  static vtkStringArrayVector *New() {
    return new vtkStringArrayVector; };

  void Delete() {
    delete this; };

  void Reset() {
    this->Container.clear(); };

  void InsertNextStringArray(vtkStringArray *stringArray) {
    this->Container.push_back(stringArray); };

  vtkStringArray *GetStringArray(int i) {
    return this->Container[static_cast<VectorType::size_type>(i)]; };

  int GetNumberOfStringArrays() {
    return static_cast<int>(this->Container.size()); };

private:
  vtkStringArrayVector() : Container() {};
  ~vtkStringArrayVector() { this->Container.clear(); };

  VectorType Container;
};

//----------------------------------------------------------------------------
vtkSortFileNames::vtkSortFileNames()
{
  this->InputFileNames = 0;
  this->NumericSort = 0;
  this->IgnoreCase = 0;
  this->Grouping = 0;
  this->SkipDirectories = 0;
  this->FileNames = vtkStringArray::New();
  this->Groups = vtkStringArrayVector::New();
}

vtkSortFileNames::~vtkSortFileNames()
{
  if (this->InputFileNames)
    {
    this->InputFileNames->Delete();
    this->InputFileNames = 0;
    }
  if (this->FileNames)
    {
    this->FileNames->Delete();
    this->FileNames = 0;
    }
  if (this->Groups)
    {
    this->Groups->Delete();
    this->Groups = 0;
    }
}

void vtkSortFileNames::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "InputFileNames:  (" << this->GetInputFileNames() << ")\n";
  os << indent << "NumericSort:  " <<
    (this->GetNumericSort() ? "On\n" : "Off\n");
  os << indent << "IgnoreCase:  " <<
    (this->GetIgnoreCase() ? "On\n" : "Off\n");
  os << indent << "Grouping:  " <<
    (this->GetGrouping() ? "On\n" : "Off\n");
  os << indent << "SkipDirectories:  " <<
    (this->GetSkipDirectories() ? "On\n" : "Off\n");

  os << indent << "NumberOfGroups: " << this->GetNumberOfGroups() << "\n";

  if (this->GetGrouping())
    {
    for (int i = 0; i < this->GetNumberOfGroups(); i++)
      {
      os << indent.GetNextIndent() << "Group[" << i << "]:  (" <<
        this->GetNthGroup(i) << ")\n";
      }
    }
  else
    {
    os << indent.GetNextIndent() << "FileNames:  ("
       << this->GetFileNames() << ")\n";
    }
}

void vtkSortFileNames::SetInputFileNames(vtkStringArray *input)
{
  vtkSetObjectBodyMacro(InputFileNames, vtkStringArray, input);
}

int vtkSortFileNames::GetNumberOfGroups()
{
  this->Update();

  return this->Groups->GetNumberOfStringArrays();
}

vtkStringArray *vtkSortFileNames::GetNthGroup(int i)
{
  this->Update();

  if (!this->GetGrouping())
    {
    vtkErrorMacro(<< "GetNthGroup(): Grouping not on.");
    return 0;
    }

  int n = this->Groups->GetNumberOfStringArrays();

  if (i >= 0 && i < n)
    {
    return this->Groups->GetStringArray(i);
    }
  else
    {
    vtkErrorMacro(<< "GetNthGroup(i): index " << i << " is out of range");
    return 0;
    }
}

vtkStringArray *vtkSortFileNames::GetFileNames()
{
  this->Update();

  return this->FileNames;
}

void vtkSortFileNames::GroupFileNames(vtkStringArray *input,
                                      vtkStringArrayVector *output)
{
  vtkstd::string baseName;
  vtkstd::string extension;
  vtkstd::string fileNamePath;
  vtkstd::string reducedName;

  vtkstd::list<unsigned int> ungroupedFiles;
  vtkstd::vector<vtkstd::string> reducedFileNames;

  unsigned int numberOfStrings = input->GetNumberOfValues();
  for (unsigned int i = 0; i < numberOfStrings; i++)
    {
    vtkstd::string& fileName = input->GetValue(i);
    extension = vtksys::SystemTools::GetFilenameLastExtension(fileName);
    fileNamePath = vtksys::SystemTools::GetFilenamePath(fileName);
    baseName = vtksys::SystemTools::GetFilenameWithoutLastExtension(fileName);

    // If extension is all digits, it is not a true extension, so
    // add it back onto the filename.  Note that the extension
    // includes the leading dot.
    int numericExtension = 1;
    for (unsigned int j = 1; j < extension.length(); j++)
      {
      if (!(extension[j] >= '0' && extension[j] <= '9'))
        {
        numericExtension = 0;
        }
      }
    if (numericExtension && extension.length() != 0)
      {
      baseName.append(extension);
      extension = "";
      }

    // Create a reduced filename that replaces all digit sequences
    // in the filename with a single digit "0". We begin by setting
    // the reduced filename to the path.
    reducedName = fileNamePath + "/";
    int inDigitBlock = 0;
    unsigned int charBlockStart = 0;
    unsigned int stringLength = static_cast<unsigned int>(baseName.length());
    for (unsigned int k = 0; k < stringLength; k++)
      {
      if (baseName[k] >= '0' && baseName[k] <= '9')
        {
        if (!inDigitBlock && k != 0)
          {
          reducedName.append(baseName.substr(charBlockStart,
                                             k-charBlockStart));
          reducedName.append("0");
          }
        inDigitBlock = 1;
        }
      else
        {
        if (inDigitBlock)
          {
          charBlockStart = k;
          inDigitBlock = 0;
          }
        }
      }
    if (!inDigitBlock)
      {
      reducedName.append(baseName.substr(charBlockStart,
                                         stringLength-charBlockStart));
      }

    // Add extension back to the filename.
    reducedName.append(extension);

    // If IgnoreCase is set, change to uppercase.
    if (this->IgnoreCase)
      {
      unsigned int n = static_cast<unsigned int>(reducedName.length());
      for (unsigned int j = 0; j < n; j++)
        {
        reducedName[j] = toupper(reducedName[j]);
        }
      }

    // The reduced filename has each block of digits replaced with "0".
    reducedFileNames.push_back(reducedName);

    // push the index onto the "ungrouped" list
    ungroupedFiles.push_back(i);
    }

  // now loop through all files and find all matches
  while (!ungroupedFiles.empty())
    {
    // get the first element in the list
    unsigned int fileIndex = ungroupedFiles.front();
    vtkstd::string& reducedFileName = reducedFileNames[fileIndex];

    vtkStringArray *newGroup = vtkStringArray::New();

    // find all matches and move them into the group
    vtkstd::list<unsigned int>::iterator p = ungroupedFiles.begin();
    while (p != ungroupedFiles.end())
      {
      unsigned int tryIndex = *p;

      if (reducedFileName == reducedFileNames[tryIndex])
        {
        newGroup->InsertNextValue(input->GetValue(tryIndex));
        p = ungroupedFiles.erase(p);
        }
      else
        {
        p++;
        }
      }

    // add the group to the output
    output->InsertNextStringArray(newGroup);
    newGroup->Delete();
    }
}

// Sort filenames lexicographically, ignoring case.
bool vtkCompareFileNamesIgnoreCase(const vtkstd::string& s1,
                                   const vtkstd::string& s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // find the minimum of the two lengths
  unsigned int n = n1;
  if (n > n2)
    {
    n = n2;
    }

  // compare the strings with no case
  for (unsigned int i = 0; i < n; i++)
    {
    char c1 = toupper(s1[i]);
    char c2 = toupper(s2[i]);

    if (c1 < c2)
      {
      return 1;
      }
    if (c1 > c2)
      {
      return 0;
      }
    }

  // if it is a tie, then the short string is "less"
  if (n1 < n2)
    {
    return 1;
    }

  // if strings are equal, use case-sensitive comparison to break tie
  if (n1 == n2)
    {
    return (s1 < s2);
    }

  // otherwise, if n1 > n2, then n1 wins
  return 0;
}

// Sort filenames numerically
bool vtkCompareFileNamesNumeric(const vtkstd::string& s1,
                                const vtkstd::string& s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // compare the strings numerically
  unsigned int i1 = 0;
  unsigned int i2 = 0;
  while (i1 < n1 && i2 < n2)
    {
    char c1 = s1[i1++];
    char c2 = s2[i2++];

    if (0 && (c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
      {
      // convert decimal numeric sequence into an integer
      unsigned int j1 = 0;
      while (c1 >= '0' && c1 <= '9')
        {
        j1 = (j1 << 3) + (j1 << 1) + (c1 - '0');
        if (i1 == n1)
          {
          break;
          }
        c1 = s1[i1++];
        }

      // convert decimal numeric sequence into an integer
      unsigned int j2 = 0;
      while (c2 >= '0' && c2 <= '9')
        {
        j2 = (j2 << 3) + (j2 << 1) + (c2 - '0');
        if (i2 == n2)
          {
          break;
          }
        c2 = s2[i2++];
        }

      // perform the numeric comparison
      if (j1 < j2)
        {
        return 1;
        }
      if (j1 > j2)
        {
        return 0;
        }
      }

    // case-insensitive lexicographic comparison of non-digits
    if ((c1 < '0' || c1 > '9') || (c2 < '0' || c2 > '9'))
      {
      if (c1 < c2)
        {
        return 1;
        }
      if (c1 > c2)
        {
        return 0;
        }
      }
    }

  // if it is a tie, then the shorter string is "less"
  if ((n1 - i1) < (n2 - i2))
    {
    return 1;
    }

  // if strings are otherwise equal, fall back to default to break tie
  if ((i1 == n1) && (i2 == n2))
    {
    return (s1 < s2);
    }

  // otherwise, return false
  return 0;
}

// Sort filenames numerically
bool vtkCompareFileNamesNumericIgnoreCase(const vtkstd::string& s1,
                                          const vtkstd::string& s2)
{
  unsigned int n1 = static_cast<unsigned int>(s1.length());
  unsigned int n2 = static_cast<unsigned int>(s2.length());

  // compare the strings numerically
  unsigned int i1 = 0;
  unsigned int i2 = 0;
  while (i1 < n1 && i2 < n2)
    {
    char c1 = s1[i1++];
    char c2 = s2[i2++];

    if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
      {
      // convert decimal numeric sequence into an integer
      unsigned int j1 = 0;
      while (c1 >= '0' && c1 <= '9')
        {
        j1 = (j1 << 3) + (j1 << 1) + (c1 - '0');
        if (i1 == n1)
          {
          break;
          }
        c1 = s1[i1++];
        }

      // convert decimal numeric sequence into an integer
      unsigned int j2 = 0;
      while (c2 >= '0' && c2 <= '9')
        {
        j2 = (j2 << 3) + (j2 << 1) + (c2 - '0');
        if (i2 == n2)
          {
          break;
          }
        c2 = s2[i2++];
        }

      // perform the numeric comparison
      if (j1 < j2)
        {
        return 1;
        }
      if (j1 > j2)
        {
        return 0;
        }
      }

    // case-insensitive lexicographic comparison of non-digits
    if ((c1 < '0' || c1 > '9') || (c2 < '0' || c2 > '9'))
      {
      c1 = toupper(c1);
      c2 = toupper(c2);

      if (c1 < c2)
        {
        return 1;
        }
      if (c1 > c2)
        {
        return 0;
        }
      }
    }

  // if it is a tie, then the shorter string is "less"
  if ((n1 - i1) < (n2 - i2))
    {
    return 1;
    }

  // if strings are otherwise equal, fall back to default to break tie
  if ((i1 == n1) && (i2 == n2))
    {
    return vtkCompareFileNamesIgnoreCase(s1, s2);
    }

  // otherwise, return false
  return 0;
}

void vtkSortFileNames::SortFileNames(vtkStringArray *input,
                                     vtkStringArray *output)
{
  // convert vtkStringArray into an STL vector
  vtkstd::vector<vtkstd::string> fileNames;
  unsigned int numberOfStrings = input->GetNumberOfValues();
  for (unsigned int j = 0; j < numberOfStrings; j++)
    {
    vtkstd::string& fileName = input->GetValue(j);

    // skip anything that is a directory
    if (this->SkipDirectories &&
        vtksys::SystemTools::FileIsDirectory(fileName.c_str()))
      {
      continue;
      }

    // build a new list
    fileNames.push_back(fileName);
    }

  // perform the sort according to the options that are set
  if (this->IgnoreCase)
    {
    if (this->NumericSort)
      {
      // numeric sort without case sensitivity
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesNumericIgnoreCase);
      }
    else
      {
      // lexicographic sort without case sensitivity
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesIgnoreCase);
      }
    }
  else
    {
    if (this->NumericSort)
      {
      // numeric sort
      vtkstd::sort(fileNames.begin(), fileNames.end(),
                   vtkCompareFileNamesNumeric);
      }
    else
      {
      // lexicographic sort (the default)
      vtkstd::sort(fileNames.begin(), fileNames.end());
      }
    }

  // build the output
  vtkstd::vector<vtkstd::string>::iterator iter = fileNames.begin();
  while (iter < fileNames.end())
    {
    output->InsertNextValue(*iter++);
    }
}

void vtkSortFileNames::Execute()
{
  // sort the input file names
  this->FileNames->Reset();
  this->SortFileNames(this->InputFileNames, this->FileNames);

  // group the sorted files if grouping is on
  this->Groups->Reset();
  if (this->Grouping)
    {
    this->GroupFileNames(this->FileNames, this->Groups);
    }
}

void vtkSortFileNames::Update()
{
  if (this->InputFileNames != 0)
    {
    if (this->GetMTime() > this->UpdateTime.GetMTime() ||
        this->InputFileNames->GetMTime() > this->UpdateTime.GetMTime())
      {
      this->Execute();
      this->UpdateTime.Modified();
      }
    }
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/event.h"

#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#else
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
#endif

#include "rtc_base/checks.h"

namespace rtc {

#if defined(WEBRTC_WIN)

Event::Event(bool manual_reset, bool initially_signaled) {
  event_handle_ = ::CreateEvent(nullptr,  // Security attributes.
                                manual_reset, initially_signaled,
                                nullptr);  // Name.
  RTC_CHECK(event_handle_);
}

Event::~Event() {
  CloseHandle(event_handle_);
}

void Event::Set() {
  SetEvent(event_handle_);
}

void Event::Reset() {
  ResetEvent(event_handle_);
}

bool Event::Wait(int milliseconds) {
  DWORD ms = (milliseconds == kForever) ? INFINITE : milliseconds;
  return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
}

#elif defined(WEBRTC_POSIX)

Event::Event(bool manual_reset, bool initially_signaled)
    : is_manual_reset_(manual_reset),
      event_status_(initially_signaled) {
  RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
  RTC_CHECK(pthread_cond_init(&event_cond_, nullptr) == 0);
}

Event::~Event() {
  pthread_mutex_destroy(&event_mutex_);
  pthread_cond_destroy(&event_cond_);
}

void Event::Set() {
  pthread_mutex_lock(&event_mutex_);
  event_status_ = true;
  pthread_cond_broadcast(&event_cond_);
  pthread_mutex_unlock(&event_mutex_);
}

void Event::Reset() {
  pthread_mutex_lock(&event_mutex_);
  event_status_ = false;
  pthread_mutex_unlock(&event_mutex_);
}

bool Event::Wait(int milliseconds) {
  int error = 0;

  struct timespec ts;
  if (milliseconds != kForever) {
    // Converting from seconds and microseconds (1e-6) plus
    // milliseconds (1e-3) to seconds and nanoseconds (1e-9).

    struct timeval tv;
    gettimeofday(&tv, nullptr);

    ts.tv_sec = tv.tv_sec + (milliseconds / 1000);
    ts.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;

    // Handle overflow.
    if (ts.tv_nsec >= 1000000000) {
      ts.tv_sec++;
      ts.tv_nsec -= 1000000000;
    }
  }

  pthread_mutex_lock(&event_mutex_);
  if (milliseconds != kForever) {
    while (!event_status_ && error == 0) {
      error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
    }
  } else {
    while (!event_status_ && error == 0)
      error = pthread_cond_wait(&event_cond_, &event_mutex_);
  }

  // NOTE(liulk): Exactly one thread will auto-reset this event. All
  // the other threads will think it's unsignaled.  This seems to be
  // consistent with auto-reset events in WEBRTC_WIN
  if (error == 0 && !is_manual_reset_)
    event_status_ = false;

  pthread_mutex_unlock(&event_mutex_);

  return (error == 0);
}

#endif

}  // namespace rtc
<commit_msg>Use monotonic clock for rtc::Event::Wait on linux and android.<commit_after>/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/event.h"

#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#else
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
#endif

#include "rtc_base/checks.h"

namespace rtc {

#if defined(WEBRTC_WIN)

Event::Event(bool manual_reset, bool initially_signaled) {
  event_handle_ = ::CreateEvent(nullptr,  // Security attributes.
                                manual_reset, initially_signaled,
                                nullptr);  // Name.
  RTC_CHECK(event_handle_);
}

Event::~Event() {
  CloseHandle(event_handle_);
}

void Event::Set() {
  SetEvent(event_handle_);
}

void Event::Reset() {
  ResetEvent(event_handle_);
}

bool Event::Wait(int milliseconds) {
  DWORD ms = (milliseconds == kForever) ? INFINITE : milliseconds;
  return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
}

#elif defined(WEBRTC_POSIX)

// On MacOS, clock_gettime is available from version 10.12, and on
// iOS, from version 10.0. So we can't use it yet.
#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
#define USE_CLOCK_GETTIME 0
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
// On Android, pthread_condattr_setclock is available from version 21. By
// default, we target a new enough version for 64-bit platforms but not for
// 32-bit platforms. For older versions, use
// pthread_cond_timedwait_monotonic_np.
#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21)
#define USE_CLOCK_GETTIME 1
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1
#else
#define USE_CLOCK_GETTIME 1
#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
#endif

Event::Event(bool manual_reset, bool initially_signaled)
    : is_manual_reset_(manual_reset),
      event_status_(initially_signaled) {
  RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
  pthread_condattr_t cond_attr;
  RTC_CHECK(pthread_condattr_init(&cond_attr) == 0);
#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
  RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
#endif
  RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0);
  pthread_condattr_destroy(&cond_attr);
}

Event::~Event() {
  pthread_mutex_destroy(&event_mutex_);
  pthread_cond_destroy(&event_cond_);
}

void Event::Set() {
  pthread_mutex_lock(&event_mutex_);
  event_status_ = true;
  pthread_cond_broadcast(&event_cond_);
  pthread_mutex_unlock(&event_mutex_);
}

void Event::Reset() {
  pthread_mutex_lock(&event_mutex_);
  event_status_ = false;
  pthread_mutex_unlock(&event_mutex_);
}

bool Event::Wait(int milliseconds) {
  int error = 0;

  struct timespec ts;
  if (milliseconds != kForever) {
#if USE_CLOCK_GETTIME
    clock_gettime(CLOCK_MONOTONIC, &ts);
#else
    struct timeval tv;
    gettimeofday(&tv, nullptr);
    ts.tv_sec = tv.tv_sec;
    ts.tv_nsec = tv.tv_usec * 1000;
#endif

    ts.tv_sec += (milliseconds / 1000);
    ts.tv_nsec += (milliseconds % 1000) * 1000000;

    // Handle overflow.
    if (ts.tv_nsec >= 1000000000) {
      ts.tv_sec++;
      ts.tv_nsec -= 1000000000;
    }
  }

  pthread_mutex_lock(&event_mutex_);
  if (milliseconds != kForever) {
    while (!event_status_ && error == 0) {
#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
      error =
          pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, &ts);
#else
      error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
#endif
    }
  } else {
    while (!event_status_ && error == 0)
      error = pthread_cond_wait(&event_cond_, &event_mutex_);
  }

  // NOTE(liulk): Exactly one thread will auto-reset this event. All
  // the other threads will think it's unsignaled.  This seems to be
  // consistent with auto-reset events in WEBRTC_WIN
  if (error == 0 && !is_manual_reset_)
    event_status_ = false;

  pthread_mutex_unlock(&event_mutex_);

  return (error == 0);
}

#endif

}  // namespace rtc
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName      :    NFCDataNoSqlModule.h
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-12-15
//    @Module           :    NFCDataNoSqlModule
//    Row,Col; ; ; ; ; ; ;
// -------------------------------------------------------------------------

//#include "stdafx.h"
#include <algorithm>
#include "NFCNoSqlModule.h"

NFCNoSqlModule::NFCNoSqlModule(NFIPluginManager* p)
{
    pPluginManager = p;
	m_pNoSqlDriver = NULL;
}

NFCNoSqlModule::~NFCNoSqlModule()
{

}

bool NFCNoSqlModule::Init()
{
    return true;
}

bool NFCNoSqlModule::Shut()
{
    delete m_pNoSqlDriver;
	m_pNoSqlDriver = NULL;

    return true;
}

bool NFCNoSqlModule::AfterInit()
{
    return true;
}

bool NFCNoSqlModule::Execute(const float fLasFrametime, const float fStartedTime)
{
    return true;
}

bool NFCNoSqlModule::ConnectSql(const std::string& strIP)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, 6379);
	}
	return false;
}

bool NFCNoSqlModule::ConnectSql(const std::string & strIP, const int nPort)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, nPort, "");
	}
	return false;
}

bool NFCNoSqlModule::ConnectSql(const std::string & strIP, const int nPort, const std::string & strPass)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, nPort, strPass);
	}
	return false;
}

NFINoSqlDriver * NFCNoSqlModule::GetDriver()
{
	return m_pNoSqlDriver;
}
NFINoSqlDriver* NFCNoSqlModule::GetDriverBySuit(const std::string& strHash)
{
	return nullptr;
}

NFINoSqlDriver* NFCNoSqlModule::GetDriverBySuit(const int strHash)
{
	return nullptr;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP)
{
	return false;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP, const int nPort)
{
	return false;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP, const int nPort, const std::string& strPass)
{
	return false;
}

NFINoSqlDriver* NFCNoSqlModule::GetDriver(const std::string& strID)
{
	return nullptr;
}

bool NFCNoSqlModule::RemoveConnectSql(const std::string& strID)
{
	return false;
}<commit_msg>used new consistent hash map class to implement distribution nosql database<commit_after>// -------------------------------------------------------------------------
//    @FileName      :    NFCDataNoSqlModule.h
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-12-15
//    @Module           :    NFCDataNoSqlModule
//    Row,Col; ; ; ; ; ; ;
// -------------------------------------------------------------------------

//#include "stdafx.h"
#include <algorithm>
#include "NFCNoSqlModule.h"

NFCNoSqlModule::NFCNoSqlModule(NFIPluginManager* p)
{
    pPluginManager = p;
	m_pNoSqlDriver = NULL;
}

NFCNoSqlModule::~NFCNoSqlModule()
{

}

bool NFCNoSqlModule::Init()
{
    return true;
}

bool NFCNoSqlModule::Shut()
{
    delete m_pNoSqlDriver;
	m_pNoSqlDriver = NULL;

    return true;
}

bool NFCNoSqlModule::AfterInit()
{
    return true;
}

bool NFCNoSqlModule::Execute(const float fLasFrametime, const float fStartedTime)
{
    return true;
}

bool NFCNoSqlModule::ConnectSql(const std::string& strIP)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, 6379);
	}
	return false;
}

bool NFCNoSqlModule::ConnectSql(const std::string & strIP, const int nPort)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, nPort, "");
	}
	return false;
}

bool NFCNoSqlModule::ConnectSql(const std::string & strIP, const int nPort, const std::string & strPass)
{
	if (!m_pNoSqlDriver)
	{
		m_pNoSqlDriver = new NFCNoSqlDriver();
		return m_pNoSqlDriver->Connect(strIP, nPort, strPass);
	}
	return false;
}

NFINoSqlDriver * NFCNoSqlModule::GetDriver()
{
	return m_pNoSqlDriver;
}
NFINoSqlDriver* NFCNoSqlModule::GetDriverBySuit(const std::string& strHash)
{
	return nullptr;
}

NFINoSqlDriver* NFCNoSqlModule::GetDriverBySuit(const int strHash)
{
	return nullptr;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP)
{
	if (!mxNoSqlDriver.ExistElement(strID))
	{
		NF_SHARE_PTR<NFINoSqlDriver> pNoSqlDriver(new NFCNoSqlDriver());
		pNoSqlDriver->Connect(strIP, 6379, "");
		return mxNoSqlDriver.AddElement(strID, pNoSqlDriver);
	}

	return false;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP, const int nPort)
{
	if (!mxNoSqlDriver.ExistElement(strID))
	{
		NF_SHARE_PTR<NFINoSqlDriver> pNoSqlDriver(new NFCNoSqlDriver());
		pNoSqlDriver->Connect(strIP, nPort, "");
		return mxNoSqlDriver.AddElement(strID, pNoSqlDriver);
	}

	return false;
}

bool NFCNoSqlModule::AddConnectSql(const std::string& strID, const std::string& strIP, const int nPort, const std::string& strPass)
{
	if (!mxNoSqlDriver.ExistElement(strID))
	{
		NF_SHARE_PTR<NFINoSqlDriver> pNoSqlDriver(new NFCNoSqlDriver());
		pNoSqlDriver->Connect(strIP, nPort, strPass);
		return mxNoSqlDriver.AddElement(strID, pNoSqlDriver);
	}

	return false;
}

NFINoSqlDriver* NFCNoSqlModule::GetDriver(const std::string& strID)
{
	return nullptr;
}

bool NFCNoSqlModule::RemoveConnectSql(const std::string& strID)
{
	return mxNoSqlDriver.RemoveElement(strID);
}<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 * OpenSim Moco: RegisterTypes_osimMoco.cpp                                   *
 * -------------------------------------------------------------------------- *
 * Copyright (c) 2017 Stanford University and the Authors                     *
 *                                                                            *
 * Author(s): Christopher Dembia                                              *
 *                                                                            *
 * Licensed 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 "RegisterTypes_osimMoco.h"

#include "Components/AccelerationMotion.h"
#include "Components/DiscreteForces.h"
#include "Components/StationPlaneContactForce.h"
#include "MocoBounds.h"
#include "MocoScaleFactor.h"
#include "MocoCasADiSolver/MocoCasADiSolver.h"
#include "MocoControlBoundConstraint.h"
#include "MocoFrameDistanceConstraint.h"
#include "MocoGoal/MocoAccelerationTrackingGoal.h"
#include "MocoGoal/MocoAngularVelocityTrackingGoal.h"
#include "MocoGoal/MocoImpulseContactTrackingGoal.h"
#include "MocoGoal/MocoControlGoal.h"
#include "MocoGoal/MocoControlTrackingGoal.h"
#include "MocoGoal/MocoGoal.h"
#include "MocoGoal/MocoImpulseTrackingGoal.h
#include "MocoGoal/MocoInitialActivationGoal.h"
#include "MocoGoal/MocoInitialForceEquilibriumDGFGoal.h"
#include "MocoGoal/MocoInitialVelocityEquilibriumDGFGoal.h"
#include "MocoGoal/MocoJointReactionGoal.h"
#include "MocoGoal/MocoMarkerFinalGoal.h"
#include "MocoGoal/MocoMarkerTrackingGoal.h"
#include "MocoGoal/MocoOrientationTrackingGoal.h"
#include "MocoGoal/MocoOutputGoal.h"
#include "MocoGoal/MocoPeriodicityGoal.h"
#include "MocoGoal/MocoStateTrackingGoal.h"
#include "MocoGoal/MocoSumSquaredStateGoal.h"
#include "MocoGoal/MocoTranslationTrackingGoal.h"
#include "MocoGoal/MocoStepTimeAsymmetryGoal.h"
#include "MocoGoal/MocoStepLengthAsymmetryGoal.h"
#include "MocoInverse.h"
#include "MocoParameter.h"
#include "MocoProblem.h"
#include "MocoStudy.h"
#include "MocoTrack.h"
#include "MocoTropterSolver.h"
#include "MocoWeightSet.h"
#include "ModelOperatorsDGF.h"
#include <exception>
#include <iostream>

using namespace OpenSim;

static osimMocoInstantiator instantiator;

OSIMMOCO_API void RegisterTypes_osimMoco() {
    try {
        Object::registerType(MocoFinalTimeGoal());
        Object::registerType(MocoAverageSpeedGoal());
        Object::registerType(MocoWeight());
        Object::registerType(MocoWeightSet());
        Object::registerType(MocoStateTrackingGoal());
        Object::registerType(MocoMarkerTrackingGoal());
        Object::registerType(MocoMarkerFinalGoal());
        Object::registerType(MocoContactTrackingGoal());
        Object::registerType(MocoControlGoal());
        Object::registerType(MocoSumSquaredStateGoal());
        Object::registerType(MocoControlTrackingGoal());
        Object::registerType(MocoInitialActivationGoal());
        Object::registerType(MocoInitialVelocityEquilibriumDGFGoal());
        Object::registerType(MocoInitialForceEquilibriumDGFGoal());
        Object::registerType(MocoJointReactionGoal());
        Object::registerType(MocoOrientationTrackingGoal());
        Object::registerType(MocoTranslationTrackingGoal());
        Object::registerType(MocoAngularVelocityTrackingGoal());
        Object::registerType(MocoAccelerationTrackingGoal());
        Object::registerType(MocoPeriodicityGoalPair());
        Object::registerType(MocoPeriodicityGoal());
        Object::registerType(MocoOutputGoal());
        Object::registerType(MocoInitialOutputGoal());
        Object::registerType(MocoFinalOutputGoal());
        Object::registerType(MocoStepTimeAsymmetryGoal());
        Object::registerType(MocoStepLengthAsymmetryGoal());
        Object::registerType(MocoBounds());
        Object::registerType(MocoInitialBounds());
        Object::registerType(MocoFinalBounds());
        Object::registerType(MocoVariableInfo());
        Object::registerType(MocoScaleFactor());
        Object::registerType(MocoParameter());
        Object::registerType(MocoPhase());
        Object::registerType(MocoProblem());
        Object::registerType(MocoStudy());

        Object::registerType(MocoInverse());
        Object::registerType(MocoTrack());

        Object::registerType(MocoTropterSolver());

        Object::registerType(MocoControlBoundConstraint());
        Object::registerType(MocoFrameDistanceConstraint());

        Object::registerType(MocoCasADiSolver());

        Object::registerType(ModOpReplaceMusclesWithDeGrooteFregly2016());
        Object::registerType(ModOpTendonComplianceDynamicsModeDGF());
        Object::registerType(ModOpIgnorePassiveFiberForcesDGF());
        Object::registerType(ModOpScaleActiveFiberForceCurveWidthDGF());

        Object::registerType(AckermannVanDenBogert2010Force());
        Object::registerType(MeyerFregly2016Force());
        Object::registerType(EspositoMiller2018Force());

        Object::registerType(DiscreteForces());
        Object::registerType(AccelerationMotion());

    } catch (const std::exception& e) {
        std::cerr << "ERROR during osimMoco Object registration:\n"
                  << e.what() << std::endl;
    }
}

osimMocoInstantiator::osimMocoInstantiator() { registerDllClasses(); }

void osimMocoInstantiator::registerDllClasses() { RegisterTypes_osimMoco(); }
<commit_msg>updated correctly the registerTypes file<commit_after>/* -------------------------------------------------------------------------- *
 * OpenSim Moco: RegisterTypes_osimMoco.cpp                                   *
 * -------------------------------------------------------------------------- *
 * Copyright (c) 2017 Stanford University and the Authors                     *
 *                                                                            *
 * Author(s): Christopher Dembia                                              *
 *                                                                            *
 * Licensed 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 "RegisterTypes_osimMoco.h"

#include "Components/AccelerationMotion.h"
#include "Components/DiscreteForces.h"
#include "Components/StationPlaneContactForce.h"
#include "MocoBounds.h"
#include "MocoScaleFactor.h"
#include "MocoCasADiSolver/MocoCasADiSolver.h"
#include "MocoControlBoundConstraint.h"
#include "MocoFrameDistanceConstraint.h"
#include "MocoGoal/MocoAccelerationTrackingGoal.h"
#include "MocoGoal/MocoAngularVelocityTrackingGoal.h"
#include "MocoGoal/MocoContactImpulseTrackingGoal.h"
#include "MocoGoal/MocoControlGoal.h"
#include "MocoGoal/MocoControlTrackingGoal.h"
#include "MocoGoal/MocoGoal.h"
#include "MocoGoal/MocoImpulseTrackingGoal.h
#include "MocoGoal/MocoInitialActivationGoal.h"
#include "MocoGoal/MocoInitialForceEquilibriumDGFGoal.h"
#include "MocoGoal/MocoInitialVelocityEquilibriumDGFGoal.h"
#include "MocoGoal/MocoJointReactionGoal.h"
#include "MocoGoal/MocoMarkerFinalGoal.h"
#include "MocoGoal/MocoMarkerTrackingGoal.h"
#include "MocoGoal/MocoOrientationTrackingGoal.h"
#include "MocoGoal/MocoOutputGoal.h"
#include "MocoGoal/MocoPeriodicityGoal.h"
#include "MocoGoal/MocoStateTrackingGoal.h"
#include "MocoGoal/MocoSumSquaredStateGoal.h"
#include "MocoGoal/MocoTranslationTrackingGoal.h"
#include "MocoGoal/MocoStepTimeAsymmetryGoal.h"
#include "MocoGoal/MocoStepLengthAsymmetryGoal.h"
#include "MocoInverse.h"
#include "MocoParameter.h"
#include "MocoProblem.h"
#include "MocoStudy.h"
#include "MocoTrack.h"
#include "MocoTropterSolver.h"
#include "MocoWeightSet.h"
#include "ModelOperatorsDGF.h"
#include <exception>
#include <iostream>

using namespace OpenSim;

static osimMocoInstantiator instantiator;

OSIMMOCO_API void RegisterTypes_osimMoco() {
    try {
        Object::registerType(MocoFinalTimeGoal());
        Object::registerType(MocoAverageSpeedGoal());
        Object::registerType(MocoWeight());
        Object::registerType(MocoWeightSet());
        Object::registerType(MocoStateTrackingGoal());
        Object::registerType(MocoMarkerTrackingGoal());
        Object::registerType(MocoMarkerFinalGoal());
        Object::registerType(MocoContactTrackingGoal());
        Object::registerType(MocoControlGoal());
        Object::registerType(MocoSumSquaredStateGoal());
        Object::registerType(MocoControlTrackingGoal());
        Object::registerType(MocoInitialActivationGoal());
        Object::registerType(MocoInitialVelocityEquilibriumDGFGoal());
        Object::registerType(MocoInitialForceEquilibriumDGFGoal());
        Object::registerType(MocoJointReactionGoal());
        Object::registerType(MocoOrientationTrackingGoal());
        Object::registerType(MocoTranslationTrackingGoal());
        Object::registerType(MocoAngularVelocityTrackingGoal());
        Object::registerType(MocoAccelerationTrackingGoal());
        Object::registerType(MocoPeriodicityGoalPair());
        Object::registerType(MocoPeriodicityGoal());
        Object::registerType(MocoOutputGoal());
        Object::registerType(MocoInitialOutputGoal());
        Object::registerType(MocoFinalOutputGoal());
        Object::registerType(MocoStepTimeAsymmetryGoal());
        Object::registerType(MocoStepLengthAsymmetryGoal());
        Object::registerType(MocoBounds());
        Object::registerType(MocoInitialBounds());
        Object::registerType(MocoFinalBounds());
        Object::registerType(MocoVariableInfo());
        Object::registerType(MocoScaleFactor());
        Object::registerType(MocoParameter());
        Object::registerType(MocoPhase());
        Object::registerType(MocoProblem());
        Object::registerType(MocoStudy());

        Object::registerType(MocoInverse());
        Object::registerType(MocoTrack());

        Object::registerType(MocoTropterSolver());

        Object::registerType(MocoControlBoundConstraint());
        Object::registerType(MocoFrameDistanceConstraint());

        Object::registerType(MocoCasADiSolver());

        Object::registerType(ModOpReplaceMusclesWithDeGrooteFregly2016());
        Object::registerType(ModOpTendonComplianceDynamicsModeDGF());
        Object::registerType(ModOpIgnorePassiveFiberForcesDGF());
        Object::registerType(ModOpScaleActiveFiberForceCurveWidthDGF());

        Object::registerType(AckermannVanDenBogert2010Force());
        Object::registerType(MeyerFregly2016Force());
        Object::registerType(EspositoMiller2018Force());

        Object::registerType(DiscreteForces());
        Object::registerType(AccelerationMotion());

    } catch (const std::exception& e) {
        std::cerr << "ERROR during osimMoco Object registration:\n"
                  << e.what() << std::endl;
    }
}

osimMocoInstantiator::osimMocoInstantiator() { registerDllClasses(); }

void osimMocoInstantiator::registerDllClasses() { RegisterTypes_osimMoco(); }
<|endoftext|>


<commit_before>#include <algorithm>
#include <cmath>

#include "TextAlignment.h"
#include "TextRenderUtils.h"

#include "components/debug/Debug.h"
#include "components/utilities/StringView.h"

TextRenderUtils::TextureGenInfo::TextureGenInfo()
{
	this->width = 0;
	this->height = 0;
}

void TextRenderUtils::TextureGenInfo::init(int width, int height)
{
	this->width = width;
	this->height = height;
}

TextRenderUtils::ColorOverrideInfo::Entry::Entry(int charIndex, const Color &color)
	: color(color)
{
	this->charIndex = charIndex;
}

int TextRenderUtils::ColorOverrideInfo::getEntryCount() const
{
	return static_cast<int>(this->entries.size());
}

std::optional<int> TextRenderUtils::ColorOverrideInfo::findEntryIndex(int charIndex) const
{
	const auto iter = std::find_if(this->entries.begin(), this->entries.end(),
		[charIndex](const ColorOverrideInfo::Entry &entry)
	{
		return entry.charIndex == charIndex;
	});

	if (iter != this->entries.end())
	{
		return static_cast<int>(std::distance(this->entries.begin(), iter));
	}
	else
	{
		return std::nullopt;
	}
}

const Color &TextRenderUtils::ColorOverrideInfo::getColor(int entryIndex) const
{
	DebugAssertIndex(this->entries, entryIndex);
	return this->entries[entryIndex].color;
}

void TextRenderUtils::ColorOverrideInfo::add(int charIndex, const Color &color)
{
	const std::optional<int> existingEntryIndex = this->findEntryIndex(charIndex);
	if (existingEntryIndex.has_value())
	{
		DebugLogError("Already have color override for char index \"" + std::to_string(charIndex) + "\".");
		return;
	}

	this->entries.emplace_back(Entry(charIndex, color));
}

void TextRenderUtils::ColorOverrideInfo::clear()
{
	this->entries.clear();
}

TextRenderUtils::TextShadowInfo::TextShadowInfo(int offsetX, int offsetY, const Color &color)
	: color(color)
{
	this->offsetX = offsetX;
	this->offsetY = offsetY;
}

TextRenderUtils::TextShadowInfo::TextShadowInfo()
{
	this->offsetX = 0;
	this->offsetY = 0;
}

void TextRenderUtils::TextShadowInfo::init(int offsetX, int offsetY, const Color &color)
{
	this->offsetX = offsetX;
	this->offsetY = offsetY;
	this->color = color;
}

std::vector<std::string_view> TextRenderUtils::getTextLines(const std::string_view &text)
{
	// @todo: might eventually handle "\r\n".
	return StringView::split(text, '\n');
}

std::vector<FontDefinition::CharID> TextRenderUtils::getLineFontCharIDs(const std::string_view &line,
	const FontDefinition &fontDef)
{
	FontDefinition::CharID fallbackCharID;
	if (!fontDef.tryGetCharacterID("?", &fallbackCharID))
	{
		DebugCrash("Couldn't get fallback font character ID from font \"" + fontDef.getName() + "\".");
	}

	// @todo: support more than ASCII
	std::vector<FontDefinition::CharID> charIDs;
	for (const char c : line)
	{
		const std::string charUtf8(1, c);
		FontDefinition::CharID charID;
		if (!fontDef.tryGetCharacterID(charUtf8.c_str(), &charID))
		{
			DebugLogWarning("Couldn't get font character ID for \"" + charUtf8 + "\".");
			charID = fallbackCharID;
		}

		charIDs.push_back(charID);
	}

	return charIDs;
}

int TextRenderUtils::getLinePixelLength(const std::vector<FontDefinition::CharID> &charIDs,
	const FontDefinition &fontDef)
{
	int width = 0;
	for (const FontDefinition::CharID charID : charIDs)
	{
		const FontDefinition::Character &fontChar = fontDef.getCharacter(charID);
		width += fontChar.getWidth();
	}

	return width;
}

TextRenderUtils::TextureGenInfo TextRenderUtils::makeTextureGenInfo(const std::string_view &text,
	const FontDefinition &fontDef, const std::optional<TextShadowInfo> &shadow, int lineSpacing)
{
	// Get the width of the longest line of text in pixels.
	int width = 0;
	const std::vector<std::string_view> textLines = TextRenderUtils::getTextLines(text);
	for (const std::string_view &line : textLines)
	{
		const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(line, fontDef);
		const int lineWidth = TextRenderUtils::getLinePixelLength(charIDs, fontDef);
		width = std::max(width, lineWidth);
	}

	const int lineCount = static_cast<int>(textLines.size());
	int height = (fontDef.getCharacterHeight() * lineCount) + (lineSpacing * std::max(0, lineCount - 1));

	if (shadow.has_value())
	{
		width += std::abs(shadow->offsetX);
		height += std::abs(shadow->offsetY);
	}

	TextureGenInfo textureGenInfo;
	textureGenInfo.init(width, height);
	return textureGenInfo;
}

std::vector<int> TextRenderUtils::makeAlignmentXOffsets(const BufferView<const std::string_view> &textLines,
	TextAlignment alignment, const FontDefinition &fontDef)
{
	std::vector<int> xOffsets(textLines.getCount());

	if (alignment == TextAlignment::Left)
	{
		// All text lines are against the left edge.
		std::fill(xOffsets.begin(), xOffsets.end(), 0);
	}
	else if (alignment == TextAlignment::Center)
	{
		auto getTextLinePixelLength = [&textLines, &fontDef](int textLinesIndex)
		{
			const std::string_view &textLine = textLines.get(textLinesIndex);
			const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(textLine, fontDef);
			return TextRenderUtils::getLinePixelLength(charIDs, fontDef);
		};

		// Find longest line then make all other lines' offsets relative to that one.
		const int longestLineIndex = [&textLines]()
		{
			const auto iter = std::max_element(textLines.get(), textLines.end(),
				[](const std::string_view &a, const std::string_view &b)
			{
				return a.size() < b.size();
			});

			if (iter == textLines.end())
			{
				DebugCrash("Couldn't find longest line for text alignment offsets.");
			}

			return static_cast<int>(std::distance(textLines.get(), iter));
		}();

		const int longestLinePixelLength = getTextLinePixelLength(longestLineIndex);

		for (int i = 0; i < textLines.getCount(); i++)
		{
			if (i != longestLineIndex)
			{
				const int linePixelLength = getTextLinePixelLength(i);
				xOffsets[i] = (longestLinePixelLength / 2) - (linePixelLength / 2);
			}
			else
			{
				// Longest line has no offset.
				xOffsets[i] = 0;
			}
		}
	}
	else
	{
		DebugNotImplementedMsg(std::to_string(static_cast<int>(alignment)));
	}

	return xOffsets;
}

void TextRenderUtils::drawChar(const FontDefinition::Character &fontChar, int dstX, int dstY, const Color &textColor,
	BufferView2D<uint32_t> &outBuffer)
{
	// @todo: clip loop ranges instead of checking in loop.
	for (int y = dstY; y < (dstY + fontChar.getHeight()); y++)
	{
		for (int x = dstX; x < (dstX + fontChar.getWidth()); x++)
		{
			if ((x >= 0) && (x < outBuffer.getWidth()) && (y >= 0) && (y < outBuffer.getHeight()))
			{
				const int srcX = x - dstX;
				const int srcY = y - dstY;
				const bool srcPixelIsColored = fontChar.get(srcX, srcY);
				if (srcPixelIsColored)
				{
					const uint32_t dstPixel = textColor.toARGB();
					outBuffer.set(x, y, dstPixel);
				}
			}
		}
	}
}

void TextRenderUtils::drawTextLine(const BufferView<const FontDefinition::CharID> &charIDs, const FontDefinition &fontDef,
	int dstX, int dstY, const Color &textColor, const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow,
	BufferView2D<uint32_t> &outBuffer)
{
	auto drawLine = [&charIDs, &fontDef, colorOverrideInfo, &outBuffer](
		int x, int y, const Color &color, bool allowColorOverrides)
	{
		int currentX = 0;
		for (int i = 0; i < charIDs.getCount(); i++)
		{
			const FontDefinition::CharID charID = charIDs.get(i);
			const FontDefinition::Character &fontChar = fontDef.getCharacter(charID);
			const Color &charColor = [colorOverrideInfo, &color, allowColorOverrides, i]() -> const Color&
			{
				if (allowColorOverrides)
				{
					const std::optional<int> entryIndex = colorOverrideInfo->findEntryIndex(i);
					if (entryIndex.has_value())
					{
						return colorOverrideInfo->getColor(*entryIndex);
					}
				}

				return color;
			}();

			TextRenderUtils::drawChar(fontChar, x + currentX, y, charColor, outBuffer);
			currentX += fontChar.getWidth();
		}
	};

	if (shadow != nullptr)
	{
		constexpr bool allowShadowColorOverrides = false;
		drawLine(dstX + shadow->offsetX, dstY + shadow->offsetY, shadow->color, allowShadowColorOverrides);
	}

	const bool allowForegroundColorOverrides = colorOverrideInfo != nullptr;
	drawLine(dstX, dstY, textColor, allowForegroundColorOverrides);
}

void TextRenderUtils::drawTextLine(const std::string_view &line, const FontDefinition &fontDef, int dstX, int dstY,
	const Color &textColor, const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow,
	BufferView2D<uint32_t> &outBuffer)
{
	const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(line, fontDef);
	const BufferView<const FontDefinition::CharID> charIdsView(charIDs.data(), static_cast<int>(charIDs.size()));
	TextRenderUtils::drawTextLine(charIdsView, fontDef, dstX, dstY, textColor, colorOverrideInfo, shadow, outBuffer);
}

void TextRenderUtils::drawTextLines(const BufferView<const std::string_view> &textLines, const FontDefinition &fontDef,
	int dstX, int dstY, const Color &textColor, TextAlignment alignment, int lineSpacing,
	const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow, BufferView2D<uint32_t> &outBuffer)
{
	const std::vector<int> xOffsets = TextRenderUtils::makeAlignmentXOffsets(textLines, alignment, fontDef);
	DebugAssert(xOffsets.size() == textLines.getCount());

	// Draw text to texture.
	// @todo: might need to adjust X and Y by some function of shadow offset. Might also need to draw all shadow lines
	// before all regular lines.
	int y = 0;
	for (int i = 0; i < textLines.getCount(); i++)
	{
		const std::string_view &textLine = textLines.get(i);
		const int xOffset = xOffsets[i];
		TextRenderUtils::drawTextLine(textLine, fontDef, dstX + xOffset, dstY + y, textColor, colorOverrideInfo,
			shadow, outBuffer);

		y += fontDef.getCharacterHeight() + lineSpacing;
	}
}
<commit_msg>Fixed text shadow offset.<commit_after>#include <algorithm>
#include <cmath>

#include "TextAlignment.h"
#include "TextRenderUtils.h"

#include "components/debug/Debug.h"
#include "components/utilities/StringView.h"

TextRenderUtils::TextureGenInfo::TextureGenInfo()
{
	this->width = 0;
	this->height = 0;
}

void TextRenderUtils::TextureGenInfo::init(int width, int height)
{
	this->width = width;
	this->height = height;
}

TextRenderUtils::ColorOverrideInfo::Entry::Entry(int charIndex, const Color &color)
	: color(color)
{
	this->charIndex = charIndex;
}

int TextRenderUtils::ColorOverrideInfo::getEntryCount() const
{
	return static_cast<int>(this->entries.size());
}

std::optional<int> TextRenderUtils::ColorOverrideInfo::findEntryIndex(int charIndex) const
{
	const auto iter = std::find_if(this->entries.begin(), this->entries.end(),
		[charIndex](const ColorOverrideInfo::Entry &entry)
	{
		return entry.charIndex == charIndex;
	});

	if (iter != this->entries.end())
	{
		return static_cast<int>(std::distance(this->entries.begin(), iter));
	}
	else
	{
		return std::nullopt;
	}
}

const Color &TextRenderUtils::ColorOverrideInfo::getColor(int entryIndex) const
{
	DebugAssertIndex(this->entries, entryIndex);
	return this->entries[entryIndex].color;
}

void TextRenderUtils::ColorOverrideInfo::add(int charIndex, const Color &color)
{
	const std::optional<int> existingEntryIndex = this->findEntryIndex(charIndex);
	if (existingEntryIndex.has_value())
	{
		DebugLogError("Already have color override for char index \"" + std::to_string(charIndex) + "\".");
		return;
	}

	this->entries.emplace_back(Entry(charIndex, color));
}

void TextRenderUtils::ColorOverrideInfo::clear()
{
	this->entries.clear();
}

TextRenderUtils::TextShadowInfo::TextShadowInfo(int offsetX, int offsetY, const Color &color)
	: color(color)
{
	this->offsetX = offsetX;
	this->offsetY = offsetY;
}

TextRenderUtils::TextShadowInfo::TextShadowInfo()
{
	this->offsetX = 0;
	this->offsetY = 0;
}

void TextRenderUtils::TextShadowInfo::init(int offsetX, int offsetY, const Color &color)
{
	this->offsetX = offsetX;
	this->offsetY = offsetY;
	this->color = color;
}

std::vector<std::string_view> TextRenderUtils::getTextLines(const std::string_view &text)
{
	// @todo: might eventually handle "\r\n".
	return StringView::split(text, '\n');
}

std::vector<FontDefinition::CharID> TextRenderUtils::getLineFontCharIDs(const std::string_view &line,
	const FontDefinition &fontDef)
{
	FontDefinition::CharID fallbackCharID;
	if (!fontDef.tryGetCharacterID("?", &fallbackCharID))
	{
		DebugCrash("Couldn't get fallback font character ID from font \"" + fontDef.getName() + "\".");
	}

	// @todo: support more than ASCII
	std::vector<FontDefinition::CharID> charIDs;
	for (const char c : line)
	{
		const std::string charUtf8(1, c);
		FontDefinition::CharID charID;
		if (!fontDef.tryGetCharacterID(charUtf8.c_str(), &charID))
		{
			DebugLogWarning("Couldn't get font character ID for \"" + charUtf8 + "\".");
			charID = fallbackCharID;
		}

		charIDs.push_back(charID);
	}

	return charIDs;
}

int TextRenderUtils::getLinePixelLength(const std::vector<FontDefinition::CharID> &charIDs,
	const FontDefinition &fontDef)
{
	int width = 0;
	for (const FontDefinition::CharID charID : charIDs)
	{
		const FontDefinition::Character &fontChar = fontDef.getCharacter(charID);
		width += fontChar.getWidth();
	}

	return width;
}

TextRenderUtils::TextureGenInfo TextRenderUtils::makeTextureGenInfo(const std::string_view &text,
	const FontDefinition &fontDef, const std::optional<TextShadowInfo> &shadow, int lineSpacing)
{
	// Get the width of the longest line of text in pixels.
	int width = 0;
	const std::vector<std::string_view> textLines = TextRenderUtils::getTextLines(text);
	for (const std::string_view &line : textLines)
	{
		const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(line, fontDef);
		const int lineWidth = TextRenderUtils::getLinePixelLength(charIDs, fontDef);
		width = std::max(width, lineWidth);
	}

	const int lineCount = static_cast<int>(textLines.size());
	int height = (fontDef.getCharacterHeight() * lineCount) + (lineSpacing * std::max(0, lineCount - 1));

	if (shadow.has_value())
	{
		width += std::abs(shadow->offsetX);
		height += std::abs(shadow->offsetY);
	}

	TextureGenInfo textureGenInfo;
	textureGenInfo.init(width, height);
	return textureGenInfo;
}

std::vector<int> TextRenderUtils::makeAlignmentXOffsets(const BufferView<const std::string_view> &textLines,
	TextAlignment alignment, const FontDefinition &fontDef)
{
	std::vector<int> xOffsets(textLines.getCount());

	if (alignment == TextAlignment::Left)
	{
		// All text lines are against the left edge.
		std::fill(xOffsets.begin(), xOffsets.end(), 0);
	}
	else if (alignment == TextAlignment::Center)
	{
		auto getTextLinePixelLength = [&textLines, &fontDef](int textLinesIndex)
		{
			const std::string_view &textLine = textLines.get(textLinesIndex);
			const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(textLine, fontDef);
			return TextRenderUtils::getLinePixelLength(charIDs, fontDef);
		};

		// Find longest line then make all other lines' offsets relative to that one.
		const int longestLineIndex = [&textLines]()
		{
			const auto iter = std::max_element(textLines.get(), textLines.end(),
				[](const std::string_view &a, const std::string_view &b)
			{
				return a.size() < b.size();
			});

			if (iter == textLines.end())
			{
				DebugCrash("Couldn't find longest line for text alignment offsets.");
			}

			return static_cast<int>(std::distance(textLines.get(), iter));
		}();

		const int longestLinePixelLength = getTextLinePixelLength(longestLineIndex);

		for (int i = 0; i < textLines.getCount(); i++)
		{
			if (i != longestLineIndex)
			{
				const int linePixelLength = getTextLinePixelLength(i);
				xOffsets[i] = (longestLinePixelLength / 2) - (linePixelLength / 2);
			}
			else
			{
				// Longest line has no offset.
				xOffsets[i] = 0;
			}
		}
	}
	else
	{
		DebugNotImplementedMsg(std::to_string(static_cast<int>(alignment)));
	}

	return xOffsets;
}

void TextRenderUtils::drawChar(const FontDefinition::Character &fontChar, int dstX, int dstY, const Color &textColor,
	BufferView2D<uint32_t> &outBuffer)
{
	// @todo: clip loop ranges instead of checking in loop.
	for (int y = dstY; y < (dstY + fontChar.getHeight()); y++)
	{
		for (int x = dstX; x < (dstX + fontChar.getWidth()); x++)
		{
			if ((x >= 0) && (x < outBuffer.getWidth()) && (y >= 0) && (y < outBuffer.getHeight()))
			{
				const int srcX = x - dstX;
				const int srcY = y - dstY;
				const bool srcPixelIsColored = fontChar.get(srcX, srcY);
				if (srcPixelIsColored)
				{
					const uint32_t dstPixel = textColor.toARGB();
					outBuffer.set(x, y, dstPixel);
				}
			}
		}
	}
}

void TextRenderUtils::drawTextLine(const BufferView<const FontDefinition::CharID> &charIDs, const FontDefinition &fontDef,
	int dstX, int dstY, const Color &textColor, const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow,
	BufferView2D<uint32_t> &outBuffer)
{
	auto drawLine = [&charIDs, &fontDef, colorOverrideInfo, &outBuffer](
		int x, int y, const Color &color, bool allowColorOverrides)
	{
		int currentX = 0;
		for (int i = 0; i < charIDs.getCount(); i++)
		{
			const FontDefinition::CharID charID = charIDs.get(i);
			const FontDefinition::Character &fontChar = fontDef.getCharacter(charID);
			const Color &charColor = [colorOverrideInfo, &color, allowColorOverrides, i]() -> const Color&
			{
				if (allowColorOverrides)
				{
					const std::optional<int> entryIndex = colorOverrideInfo->findEntryIndex(i);
					if (entryIndex.has_value())
					{
						return colorOverrideInfo->getColor(*entryIndex);
					}
				}

				return color;
			}();

			TextRenderUtils::drawChar(fontChar, x + currentX, y, charColor, outBuffer);
			currentX += fontChar.getWidth();
		}
	};

	int foregroundDstX = dstX;
	int foregroundDstY = dstY;
	if (shadow != nullptr)
	{
		foregroundDstX += std::max(-shadow->offsetX, 0);
		foregroundDstY += std::max(-shadow->offsetY, 0);

		const int shadowDstX = dstX + std::max(shadow->offsetX, 0);
		const int shadowDstY = dstY + std::max(shadow->offsetY, 0);
		constexpr bool allowShadowColorOverrides = false;
		drawLine(shadowDstX, shadowDstY, shadow->color, allowShadowColorOverrides);
	}

	const bool allowForegroundColorOverrides = colorOverrideInfo != nullptr;
	drawLine(foregroundDstX, foregroundDstY, textColor, allowForegroundColorOverrides);
}

void TextRenderUtils::drawTextLine(const std::string_view &line, const FontDefinition &fontDef, int dstX, int dstY,
	const Color &textColor, const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow,
	BufferView2D<uint32_t> &outBuffer)
{
	const std::vector<FontDefinition::CharID> charIDs = TextRenderUtils::getLineFontCharIDs(line, fontDef);
	const BufferView<const FontDefinition::CharID> charIdsView(charIDs.data(), static_cast<int>(charIDs.size()));
	TextRenderUtils::drawTextLine(charIdsView, fontDef, dstX, dstY, textColor, colorOverrideInfo, shadow, outBuffer);
}

void TextRenderUtils::drawTextLines(const BufferView<const std::string_view> &textLines, const FontDefinition &fontDef,
	int dstX, int dstY, const Color &textColor, TextAlignment alignment, int lineSpacing,
	const ColorOverrideInfo *colorOverrideInfo, const TextShadowInfo *shadow, BufferView2D<uint32_t> &outBuffer)
{
	const std::vector<int> xOffsets = TextRenderUtils::makeAlignmentXOffsets(textLines, alignment, fontDef);
	DebugAssert(xOffsets.size() == textLines.getCount());

	// Draw text to texture.
	// @todo: might need to adjust X and Y by some function of shadow offset. Might also need to draw all shadow lines
	// before all regular lines.
	int y = 0;
	for (int i = 0; i < textLines.getCount(); i++)
	{
		const std::string_view &textLine = textLines.get(i);
		const int xOffset = xOffsets[i];
		TextRenderUtils::drawTextLine(textLine, fontDef, dstX + xOffset, dstY + y, textColor, colorOverrideInfo,
			shadow, outBuffer);

		y += fontDef.getCharacterHeight() + lineSpacing;
	}
}
<|endoftext|>


<commit_before>//
//  TextureTarget.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#ifndef TextureTarget_hpp
#define TextureTarget_hpp

#include "OpenGL.hpp"
#include "Shaders/Shader.hpp"
#include <memory>

namespace OpenGL {

/*!
	A @c TextureTarget is a framebuffer that can be bound as a texture. So this class
	handles render-to-texture framebuffer objects.
*/
class TextureTarget {
	public:
		/*!
			Creates a new texture target.

			Throws ErrorFramebufferIncomplete if creation fails. Leaves both the generated texture and framebuffer bound.

			@param width The width of target to create.
			@param height The height of target to create.
			@param texture_unit A texture unit on which to bind the texture.
		*/
		TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, GLint mag_filter);
		~TextureTarget();

		/*!
			Binds this target as a framebuffer and sets the @c glViewport accordingly.
		*/
		void bind_framebuffer();

		/*!
			Binds this target as a texture.
		*/
		void bind_texture();

		/*!
			@returns the width of the texture target.
		*/
		GLsizei get_width() {
			return width_;
		}

		/*!
			@returns the height of the texture target.
		*/
		GLsizei get_height() {
			return height_;
		}

		/*!
			Draws this texture to the currently-bound framebuffer, which has the aspect ratio
			@c aspect_ratio. This texture will fill the height of the frame buffer, and pick
			an appropriate width based o the aspect ratio.

			@c colour_threshold sets a threshold test that each colour must satisfy to be
			output. A threshold of 0.0f means that all colours will pass through. A threshold
			of 0.5f means that only colour components above 0.5f will pass through, with
			0.5f being substituted elsewhere. This provides a way to ensure that the sort of
			persistent low-value errors that can result from an IIR are hidden.
		*/
		void draw(float aspect_ratio, float colour_threshold = 0.0f);

		enum {
			ErrorFramebufferIncomplete
		};

	private:
		GLuint framebuffer_ = 0, texture_ = 0;
		GLsizei width_ = 0, height_ = 0;
		GLsizei expanded_width_ = 0, expanded_height_ = 0;
		GLenum texture_unit_ = 0;

		std::unique_ptr<Shader> pixel_shader_;
		GLuint drawing_vertex_array_ = 0, drawing_array_buffer_ = 0;
		float set_aspect_ratio_ = 0.0f;

		GLint threshold_uniform_;
};

}

#endif /* TextureTarget_hpp */
<commit_msg>Corrects typo.<commit_after>//
//  TextureTarget.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#ifndef TextureTarget_hpp
#define TextureTarget_hpp

#include "OpenGL.hpp"
#include "Shaders/Shader.hpp"
#include <memory>

namespace OpenGL {

/*!
	A @c TextureTarget is a framebuffer that can be bound as a texture. So this class
	handles render-to-texture framebuffer objects.
*/
class TextureTarget {
	public:
		/*!
			Creates a new texture target.

			Throws ErrorFramebufferIncomplete if creation fails. Leaves both the generated texture and framebuffer bound.

			@param width The width of target to create.
			@param height The height of target to create.
			@param texture_unit A texture unit on which to bind the texture.
		*/
		TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit, GLint mag_filter);
		~TextureTarget();

		/*!
			Binds this target as a framebuffer and sets the @c glViewport accordingly.
		*/
		void bind_framebuffer();

		/*!
			Binds this target as a texture.
		*/
		void bind_texture();

		/*!
			@returns the width of the texture target.
		*/
		GLsizei get_width() {
			return width_;
		}

		/*!
			@returns the height of the texture target.
		*/
		GLsizei get_height() {
			return height_;
		}

		/*!
			Draws this texture to the currently-bound framebuffer, which has the aspect ratio
			@c aspect_ratio. This texture will fill the height of the frame buffer, and pick
			an appropriate width based on the aspect ratio.

			@c colour_threshold sets a threshold test that each colour must satisfy to be
			output. A threshold of 0.0f means that all colours will pass through. A threshold
			of 0.5f means that only colour components above 0.5f will pass through, with
			0.5f being substituted elsewhere. This provides a way to ensure that the sort of
			persistent low-value errors that can result from an IIR are hidden.
		*/
		void draw(float aspect_ratio, float colour_threshold = 0.0f);

		enum {
			ErrorFramebufferIncomplete
		};

	private:
		GLuint framebuffer_ = 0, texture_ = 0;
		GLsizei width_ = 0, height_ = 0;
		GLsizei expanded_width_ = 0, expanded_height_ = 0;
		GLenum texture_unit_ = 0;

		std::unique_ptr<Shader> pixel_shader_;
		GLuint drawing_vertex_array_ = 0, drawing_array_buffer_ = 0;
		float set_aspect_ratio_ = 0.0f;

		GLint threshold_uniform_;
};

}

#endif /* TextureTarget_hpp */
<|endoftext|>


<commit_before>//!
//! @author Yue Wang
//! @date   01.12.2014
//!
//! Exercise 10.1:
//! The algorithm header defines a function named count that, like find,
//! takes a pair of iterators and a value.count returns a count of how
//! often that value appears.
//! Read a sequence of ints into a vector and print the count of how many
//! elements have a given value.
//!
//! Exercise 10.2:
//! Repeat the previous program, but read values into a list of strings.
//!

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <list>

int main()
{
    //! 10.1
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 6, 6, 2};
    std::cout << "ex 10.01: " << std::count(v.cbegin(), v.cend(), 6)
              << std::endl;

    //! 10.2
    std::list<std::string> l = {"aa", "aaa", "aa", "cc"};
    std::cout << "ex 10.02: " << std::count(l.cbegin(), l.cend(), "aa")
              << std::endl;

    return 0;
}
//! output:
//!
// ex 10.01: 3
// ex 10.02: 2
<commit_msg>Update ex10_01_02.cpp<commit_after>//!
//! @author Yue Wang
//! @date   01.12.2014
//!
//! Exercise 10.1:
//! The algorithm header defines a function named count that, like find,
//! takes a pair of iterators and a value.count returns a count of how
//! often that value appears.
//! Read a sequence of ints into a vector and print the count of how many
//! elements have a given value.
//!
//! Exercise 10.2:
//! Repeat the previous program, but read values into a list of strings.
//!

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
#include <string>

using namespace std;

int main()
{
    //! 10.1
    vector<int> ivec{1, 2, 3, 4, 5, 6, 6, 6, 2};
    cout<<"ex 10.01: "<<count(ivec.cbegin(), ivec.cend(), 6)<<endl;

    //! 10.2
    list<string> slst{"aa", "aaa", "aa", "cc"};
    cout<<"ex 10.02: "<<count(slst.cbegin(), slst.cend(), "aa")<<endl;
}

//! output:
//!
// ex 10.01: 3
// ex 10.02: 2
<|endoftext|>


<commit_before>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiWaveReader.h"
#include "nuiAudioConvert.h"
#include "nuiChunksDefinitions.h"

nuiWaveReader::nuiWaveReader(nglIStream& rStream) : nuiChunkSampleReader(rStream)
{
  mrStream.SetEndian(eEndianLittle);
}

nuiWaveReader::nuiWaveReader(const nuiWaveReader& rReader, nglIStream& rStream) :
nuiChunkSampleReader(rReader, rStream)
{
  mrStream.SetEndian(eEndianLittle);
}

nuiWaveReader::~nuiWaveReader()
{
}

nuiSampleReader* nuiWaveReader::Clone(nglIStream& rStream) const
{
  nuiWaveReader* pReader = new nuiWaveReader(*this, rStream);
  pReader->SetPosition(0);
  return pReader;
}

void nuiWaveReader::SetPosition(uint32 position)
{
  if (!mInitialized)
    return;

  Chunk* pDataChunk = GetChunk("data");

  nglFileOffset newStreamPosition = pDataChunk->mDataPosition + mInfo.GetChannels() * (mInfo.GetBitsPerSample() / 8) * position;
  nglFileOffset newPos = mrStream.SetPos(newStreamPosition);
  NGL_ASSERT(newPos == newStreamPosition);
  mPosition = position;
}

bool nuiWaveReader::ReadInfo()
{
  ScanAllChunks();

  uint16 Format = eWaveFormatUnknown;
  uint16 NbChannels = 0;
  uint32 SamplesPerSec = 0;
  uint32 AvgBytesPerSec = 0;
  uint16 BlockAlign = 0;
  uint16 BitsPerSample = 0;
  uint32 NbSamples = 0;

  bool res = false;

  res = GoToChunk("RIFF");
  if (!res)
    return false;
  std::vector<char> fileFormat(4);
  char* waveFormat = "WAVE";
  for(uint32 i = 0; i < 4; i++)
  {
    if( 1 != mrStream.ReadUInt8((uint8*)&(fileFormat[i]), 1))
      return false;
    if (fileFormat[i] != waveFormat[i])
      return false; // this stream is not a wave stream
  }
  mInfo.SetFileFormat(eAudioWave);

  res = GoToChunk("fmt ");
  if (!res)
    return false;

  //Read all parameters given in "fmt" chunk
  if( 1 != mrStream.ReadUInt16(&Format,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&NbChannels,1))
    return false;
  if( 1 != mrStream.ReadUInt32(&SamplesPerSec,1))
    return false;
  if( 1 != mrStream.ReadUInt32(&AvgBytesPerSec,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&BlockAlign,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&BitsPerSample,1))
    return false;

  mInfo.SetFormatTag(Format);
  mInfo.SetSampleRate(SamplesPerSec);
  mInfo.SetChannels(NbChannels);
  mInfo.SetBitsPerSample(BitsPerSample);

  //get number of sample frames
  for(uint32 i = 0; i < mChunks.size(); i++)
  {
    if(mChunks[i]->CompareId("data"))  //attempt to reach "data" Chunk
    {
      NbSamples = mChunks[i]->mDataSize;
      mInfo.SetSampleFrames(NbSamples * 8 / BitsPerSample / NbChannels);
      break;
    }
  }

  mInfo.SetStartFrame(0);
  mInfo.SetStopFrame(mInfo.GetSampleFrames());

  return true;
}

uint32 nuiWaveReader::ReadIN(void* pBuffer, uint32 sampleframes, nuiSampleBitFormat format)
{
  nglFileOffset oldPos = mrStream.GetPos();
  SetPosition(mPosition);
  nglFileOffset newPos = mrStream.GetPos();
  const uint64 SamplePointsToRead = sampleframes * mInfo.GetChannels();
  uint64 SampleFramesRead = 0;
  const uint32 channels = mInfo.GetChannels();
  switch(format)
  {
    case eSampleInt16 :
    {
      switch (mInfo.GetBitsPerSample())
      {
        case 8:
        {
          int16* pTempInt16 = (int16*)pBuffer;
          uint32 sizeRead = mrStream.ReadUInt8(((uint8*)pTempInt16) + SamplePointsToRead , SamplePointsToRead);
          nuiAudioConvert_Unsigned8bitsBufferTo16Bits(pTempInt16, sizeRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        case 16:
        {
          uint32 sizeRead = mrStream.ReadInt16((int16*)pBuffer, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        case 24:
        case 32:
        default:
          NGL_ASSERT(0);
          SampleFramesRead = 0;
          break;
      }
    }
      break;

    case eSampleFloat32 :
    {
      switch (mInfo.GetBitsPerSample())
      {
        case 8:
        {
          float* pTempFloat = (float*)pBuffer;
          uint32 sizeRead = mrStream.ReadUInt8((uint8*)pTempFloat + 3 * SamplePointsToRead , SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
          nuiAudioConvert_Unsigned8bitsBufferToFloat(pTempFloat, sizeRead);
        }
          break;

        case 16:
        {
          float* pTempFloat = (float*)pBuffer;

          uint32 sizeRead = mrStream.ReadInt16((int16*)pTempFloat + SamplePointsToRead, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
          nuiAudioConvert_16bitsBufferToFloat(pTempFloat, sizeRead);
        }
          break;

        case 24:
        {
          float* pTempFloat = (float*)pBuffer;
          uint8* pTempBuffer;
          pTempBuffer = new uint8[SamplePointsToRead * 3]; //nb of sample points * 3 bytes (24 bits) = nb of bytes to read

          uint32 sizeRead = mrStream.ReadUInt8(pTempBuffer, SamplePointsToRead * 3) / 3; //divide by 3 to get actual number of read samples
          SampleFramesRead = sizeRead / channels / 3;
          for (uint64 i = 0; i < sizeRead; i++)
          {
            pTempFloat[i] = nuiAudioConvert_24bitsToFloatFromLittleEndian(pTempBuffer + (3 * i));
          }

          delete[] pTempBuffer;
        }
          break;

        case 32:
        {
          uint32 sizeRead = mrStream.ReadFloat((float*)pBuffer, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        default:
          NGL_ASSERT(0);
          SampleFramesRead = 0;
          break;
      }
    }
      break;
    default:
      NGL_ASSERT(0);
      SampleFramesRead = 0;
      break;
  }

  mPosition += SampleFramesRead;
  return SampleFramesRead;
}

<commit_msg>fixed wave 24 bits int samples loading<commit_after>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiWaveReader.h"
#include "nuiAudioConvert.h"
#include "nuiChunksDefinitions.h"

nuiWaveReader::nuiWaveReader(nglIStream& rStream) : nuiChunkSampleReader(rStream)
{
  mrStream.SetEndian(eEndianLittle);
}

nuiWaveReader::nuiWaveReader(const nuiWaveReader& rReader, nglIStream& rStream) :
nuiChunkSampleReader(rReader, rStream)
{
  mrStream.SetEndian(eEndianLittle);
}

nuiWaveReader::~nuiWaveReader()
{
}

nuiSampleReader* nuiWaveReader::Clone(nglIStream& rStream) const
{
  nuiWaveReader* pReader = new nuiWaveReader(*this, rStream);
  pReader->SetPosition(0);
  return pReader;
}

void nuiWaveReader::SetPosition(uint32 position)
{
  if (!mInitialized)
    return;

  Chunk* pDataChunk = GetChunk("data");

  nglFileOffset newStreamPosition = pDataChunk->mDataPosition + mInfo.GetChannels() * (mInfo.GetBitsPerSample() / 8) * position;
  nglFileOffset newPos = mrStream.SetPos(newStreamPosition);
  NGL_ASSERT(newPos == newStreamPosition);
  mPosition = position;
}

bool nuiWaveReader::ReadInfo()
{
  ScanAllChunks();

  uint16 Format = eWaveFormatUnknown;
  uint16 NbChannels = 0;
  uint32 SamplesPerSec = 0;
  uint32 AvgBytesPerSec = 0;
  uint16 BlockAlign = 0;
  uint16 BitsPerSample = 0;
  uint32 NbSamples = 0;

  bool res = false;

  res = GoToChunk("RIFF");
  if (!res)
    return false;
  std::vector<char> fileFormat(4);
  char* waveFormat = "WAVE";
  for(uint32 i = 0; i < 4; i++)
  {
    if( 1 != mrStream.ReadUInt8((uint8*)&(fileFormat[i]), 1))
      return false;
    if (fileFormat[i] != waveFormat[i])
      return false; // this stream is not a wave stream
  }
  mInfo.SetFileFormat(eAudioWave);

  res = GoToChunk("fmt ");
  if (!res)
    return false;

  //Read all parameters given in "fmt" chunk
  if( 1 != mrStream.ReadUInt16(&Format,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&NbChannels,1))
    return false;
  if( 1 != mrStream.ReadUInt32(&SamplesPerSec,1))
    return false;
  if( 1 != mrStream.ReadUInt32(&AvgBytesPerSec,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&BlockAlign,1))
    return false;
  if( 1 != mrStream.ReadUInt16(&BitsPerSample,1))
    return false;

  mInfo.SetFormatTag(Format);
  mInfo.SetSampleRate(SamplesPerSec);
  mInfo.SetChannels(NbChannels);
  mInfo.SetBitsPerSample(BitsPerSample);

  //get number of sample frames
  for(uint32 i = 0; i < mChunks.size(); i++)
  {
    if(mChunks[i]->CompareId("data"))  //attempt to reach "data" Chunk
    {
      NbSamples = mChunks[i]->mDataSize;
      mInfo.SetSampleFrames(NbSamples * 8 / BitsPerSample / NbChannels);
      break;
    }
  }

  mInfo.SetStartFrame(0);
  mInfo.SetStopFrame(mInfo.GetSampleFrames());

  return true;
}

uint32 nuiWaveReader::ReadIN(void* pBuffer, uint32 sampleframes, nuiSampleBitFormat format)
{
  nglFileOffset oldPos = mrStream.GetPos();
  SetPosition(mPosition);
  nglFileOffset newPos = mrStream.GetPos();
  const uint64 SamplePointsToRead = sampleframes * mInfo.GetChannels();
  uint64 SampleFramesRead = 0;
  const uint32 channels = mInfo.GetChannels();
  switch(format)
  {
    case eSampleInt16 :
    {
      switch (mInfo.GetBitsPerSample())
      {
        case 8:
        {
          int16* pTempInt16 = (int16*)pBuffer;
          uint32 sizeRead = mrStream.ReadUInt8(((uint8*)pTempInt16) + SamplePointsToRead , SamplePointsToRead);
          nuiAudioConvert_Unsigned8bitsBufferTo16Bits(pTempInt16, sizeRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        case 16:
        {
          uint32 sizeRead = mrStream.ReadInt16((int16*)pBuffer, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        case 24:
        case 32:
        default:
          NGL_ASSERT(0);
          SampleFramesRead = 0;
          break;
      }
    }
      break;

    case eSampleFloat32 :
    {
      switch (mInfo.GetBitsPerSample())
      {
        case 8:
        {
          float* pTempFloat = (float*)pBuffer;
          uint32 sizeRead = mrStream.ReadUInt8((uint8*)pTempFloat + 3 * SamplePointsToRead , SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
          nuiAudioConvert_Unsigned8bitsBufferToFloat(pTempFloat, sizeRead);
        }
          break;

        case 16:
        {
          float* pTempFloat = (float*)pBuffer;

          uint32 sizeRead = mrStream.ReadInt16((int16*)pTempFloat + SamplePointsToRead, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
          nuiAudioConvert_16bitsBufferToFloat(pTempFloat, sizeRead);
        }
          break;

        case 24:
        {
          float* pTempFloat = (float*)pBuffer;
          uint8* pTempBuffer;
          pTempBuffer = new uint8[SamplePointsToRead * 3]; //nb of sample points * 3 bytes (24 bits) = nb of bytes to read

          uint32 sizeRead = mrStream.ReadUInt8(pTempBuffer, SamplePointsToRead * 3);
          SampleFramesRead = (sizeRead / channels) / 3;
          for (uint64 i = 0; i < sizeRead / 3; i++)
          {
            pTempFloat[i] = nuiAudioConvert_24bitsToFloatFromLittleEndian(pTempBuffer + (3 * i));
          }

          delete[] pTempBuffer;
        }
          break;

        case 32:
        {
          uint32 sizeRead = mrStream.ReadFloat((float*)pBuffer, SamplePointsToRead);
          SampleFramesRead = sizeRead / channels;
        }
          break;

        default:
          NGL_ASSERT(0);
          SampleFramesRead = 0;
          break;
      }
    }
      break;
    default:
      NGL_ASSERT(0);
      SampleFramesRead = 0;
      break;
  }

  mPosition += SampleFramesRead;
  return SampleFramesRead;
}

<|endoftext|>


<commit_before>//!
//! Exercise 15.24:
//! What kinds of classes need a virtual destructor? What operations must a
//! virtual destructor perform?
//  Generally, a base class should define a virtual destructor.
//  The destructor needs to be virtual to allow objects in the inheritance
//  hierarchy to be dynamically allocated and destroyed.
//!
//! Exercise 15.25:
//! Why did we define a default constructor for Disc_quote? What effect, if
//! any, would removing that constructor have on the behavior of Bulk_quote?
//  Without it, when building the statement below, the compiler would conplain
//  that:
//  note: 'Bulk_quote::Bulk_quote()' is implicitly deleted because the default
//  definition would be ill-formed.
//  The reason is that a constructor taking 4 parameters has been defined, which
//  prevented the compiler generate synthesized version default constructor. As a
//  result, the default constructor of any class derived from it has been defined
//  as deleted. Thus the default constructor must be defined explicitly so that
//  the derived classes can call it when executing its default constructor.
//!

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"

int main()
{
    //Bulk_quote b;
}
<commit_msg>Update ex15.24.25.cpp<commit_after>//!
//! Exercise 15.24:
//! What kinds of classes need a virtual destructor? What operations must a
//! virtual destructor perform?
//  Generally, a base class should define a virtual destructor.
//  The destructor needs to be virtual to allow objects in the inheritance
//  hierarchy to be dynamically allocated and destroyed.
//!
//! Exercise 15.25:
//! Why did we define a default constructor for Disc_quote? What effect, if
//! any, would removing that constructor have on the behavior of Bulk_quote?
//  Without it, when building the statement below, the compiler would complain
//  that:
//  note: 'Bulk_quote::Bulk_quote()' is implicitly deleted because the default
//  definition would be ill-formed.
//  The reason is that a constructor taking 4 parameters has been defined, which
//  prevented the compiler generate synthesized version default constructor. As a
//  result, the default constructor of any class derived from it has been defined
//  as deleted. Thus the default constructor must be defined explicitly so that
//  the derived classes can call it when executing its default constructor.
//!

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"

int main()
{
    //Bulk_quote b;
}
<|endoftext|>