<commit_before>/******************************************************************/
/**
**  @file errors.cpp
**  @brief Error-handling routines.
**
**  Created Dec. 97 from earlier routine embedded in child.cpp
**  $Id: errors.cpp,v 1.7 2004-01-07 10:53:24 childcvs Exp $
*/
/******************************************************************/

#include "errors.h"

#include <stdlib.h>
#if !defined(HAVE_NO_NAMESPACE)
# include <iostream>
using namespace std;
#else
# include <iostream.h>
#endif

#define CHILD_ABORT_ON_ERROR "CHILD_ABORT_ON_ERROR"
#define CHILD_ABORT_ON_WARNING "CHILD_ABORT_ON_WARNING"

/*****************************************************************************\
**
**  ReportFatalError:  This is an error-handling routine that prints the
**                     message errMsg then halts the program.
**
**      Parameters:     errMsg -- error message
**      Called by:
**      Created: 12/96 GT
**
\*****************************************************************************/
void ReportFatalError( const char *errMsg )
{
  cout << errMsg <<endl;
  cout << "That was a fatal error, my friend!" <<endl;
  if (getenv(CHILD_ABORT_ON_ERROR) != NULL)
    abort();
  cout << "(Set \"" CHILD_ABORT_ON_ERROR "\" to generate a crash.)" <<endl;
  exit(1);
}

/*****************************************************************************\
**
**  ReportWarning:  This is an error-handling routine that prints the
**                     message errMsg but does not halt the program unless
**                     the environment variable CHILD_ABORT_ON_WARNING is set.
**
**      Parameters:     errMsg -- error message
**      Called by:
**      Created: 9/03 SL
**
\*****************************************************************************/
void ReportWarning( const char *errMsg )
{
  cout << "WARNING: " << errMsg <<endl;
  if (getenv(CHILD_ABORT_ON_WARNING) != NULL)
    abort();
  cout << "(Set \"" CHILD_ABORT_ON_WARNING "\" to generate a crash.)" <<endl;
}

<commit_msg>(Arnaud) more explanations.<commit_after>/******************************************************************/
/**
**  @file errors.cpp
**  @brief Error-handling routines.
**
**  Created Dec. 97 from earlier routine embedded in child.cpp
**  $Id: errors.cpp,v 1.8 2004-05-26 16:24:43 childcvs Exp $
*/
/******************************************************************/

#include "errors.h"

#include <stdlib.h>
#if !defined(HAVE_NO_NAMESPACE)
# include <iostream>
using namespace std;
#else
# include <iostream.h>
#endif

#define CHILD_ABORT_ON_ERROR "CHILD_ABORT_ON_ERROR"
#define CHILD_ABORT_ON_WARNING "CHILD_ABORT_ON_WARNING"

/*****************************************************************************\
**
**  ReportFatalError:  This is an error-handling routine that prints the
**                     message errMsg then halts the program.
**
**      Parameters:     errMsg -- error message
**      Called by:
**      Created: 12/96 GT
**
\*****************************************************************************/
void ReportFatalError( const char *errMsg )
{
  cout << errMsg <<endl;
  cout << "That was a fatal error, my friend!" <<endl;
  if (getenv(CHILD_ABORT_ON_ERROR) != NULL)
    abort();
  cout << "(Set \"" CHILD_ABORT_ON_ERROR "\" to generate a crash.)" <<endl;
  exit(1);
}

/*****************************************************************************\
**
**  ReportWarning:  This is an error-handling routine that prints the
**                     message errMsg but does not halt the program unless
**                     the environment variable CHILD_ABORT_ON_WARNING is set.
**
**      Parameters:     errMsg -- error message
**      Called by:
**      Created: 9/03 SL
**
\*****************************************************************************/
void ReportWarning( const char *errMsg )
{
  cout << "WARNING: " << errMsg <<endl;
  if (getenv(CHILD_ABORT_ON_WARNING) != NULL)
    abort();
  cout <<
    "(Set \"" CHILD_ABORT_ON_WARNING "\" to generate a crash."
    "\n.e.g. \"env " CHILD_ABORT_ON_WARNING "=1 child ...\")"
       <<endl;
}

<|endoftext|>


<commit_before>/*
**  tStorm.cpp
**
**  Functions for tStorm objects.
**  A tStorm object generates random storms assuming an exponential
**  distribution of rainfall intensity, storm duration, and time to the
**  next storm. It is essentially an implementation of the model of
**  P. Eagleson, 1978b, Water Resources Research. Its services include
**  reading the necessary parameters from a tInputFile, generating a new
**  storm, and reporting its various values.
**    If you want to provide an option for NOT having storms vary
**  randomly, you can do so by setting optVariable to zero on initialization.
**    The GammaDev() function is provided for future reference; it is not
**  actually used in version 1.0.
**    tStorm objects could be easily modified (or inherited from) to use
**  different distributions. They can also be modified to create objects
**  for other random processes such as river flows, etc.
**    The random number generation routine ran3() from Numerical Recipes
**  is included in this file.
**
**  Version 1.0, Greg Tucker, November 1997.
**  $Id: tStorm.cpp,v 1.10 1998-06-04 21:27:44 gtucker Exp $
*/

#include <math.h>
#include "../Mathutil/mathutil.h"
#include "tStorm.h"

/*
**  tStorm::tStorm:  Constructor for storms. The default constructor
**                   assigns a value of unity to storm depth, duration,
**                   and interstorm duration.
*/
tStorm::tStorm( int optvar )
{
   optVariable = optvar;
   pMean = 1.0;
   stdurMean = 1.0;
   istdurMean = 1.0;
   p = 1.0;
   stdur = 1.0;
   istdur = 1.0;
   srand( 0 );
}

/*
**  tStorm::tStorm:  The constructor that's really used assigns values for
**                   mean storm depth, duration, and interstorm duration,
**                   initializes current depth, etc, to the mean values,
**                   and initializes the random number generator.
*/
tStorm::tStorm( double mp, double ms, double mis, unsigned sd, int optvar )
{
   optVariable = optvar;
   pMean = mp;
   stdurMean = ms;
   istdurMean = mis;
   p = pMean;
   stdur = stdurMean;
   istdur = istdurMean;
   seed = sd;
   srand( seed );
}

/*
**  tStorm::tStorm
**
**  Alternative constructor that reads parameters directly from a tInputFile
**  object. Reads option for variable storms (normally this is "yes"---that's
**  the point of these objects---but a user may wish to switch off variation
**  as a test), mean values for rainfall intensity, duration, and interstorm
**  period, and a random seed to initialize the random number generator.
*/
tStorm::tStorm( tInputFile &infile )
{
   optVariable = infile.ReadItem( optVariable, "OPTVAR" );
   pMean = infile.ReadItem( pMean, "PMEAN" );
   stdurMean = infile.ReadItem( stdurMean, "STDUR" );
   istdurMean = infile.ReadItem( istdurMean, "ISTDUR" );
   p = pMean;
   stdur = stdurMean;
   istdur = istdurMean;
   seed = infile.ReadItem( seed, "SEED" );
   srand( seed );
}

/*
**  tStorm::GenerateStorm
**
**  Generates a new storm by drawing new values of p, stdur, and istdur from
**  an exponential distribution and updating the random seed.
**    If the minp parameter is greater than zero, the function will keep
**  picking storms until it finds one with p>minp. The total elapsed time,
**  including the rejected storms and their associated interstorm periods,
**  is stored istdur.
**
**  Parameters:  minp -- minimum value of rainfall rate p (default 0)
**  Members updated:  p, stdur, istdur take on new random values
**  Assumptions:  pMean > 0
*/
void tStorm::GenerateStorm( double minp, double mind )
{
   if( optVariable )
   {
      stdur = 0;
      istdur = 0;
      do
      {
         p = pMean*ExpDev( &seed );
         istdur += istdurMean*ExpDev( &seed ) + stdur;
         stdur = stdurMean*ExpDev( &seed );
         /*cout << "P " << p << "  ST " << stdur << "  IST " << istdur
              << "  DP " << p*stdur << endl;*/
         srand( seed );
      } while( p<=minp && (p*stdur)<=mind );
   }
}

/*
**  tStorm::ExpDev:  Finds a random number with an exponential distribution
**                   (adapted from Numerical Recipes).
*/
double tStorm::ExpDev( long *idum )
{
    double dum;

    do
        dum = ran3( idum );
    while( dum==0.0 );
    return -log(dum);
}

/*
**  getStormDuration
**
**  Returns the storm duration.
*/
double tStorm::getStormDuration()
{
   return stdur;
}

/*
**  InterstormDur
**
**  Returns the interstorm duration.
*/
double tStorm::interstormDur()
{
   return istdur;
}

/*
**  getRainrate
**
**  Returns the rainfall rate.
*/
double tStorm::getRainrate()
{
   return p;
}

double tStorm::getMeanStormDur() const {return stdurMean;}
double tStorm::getMeanInterstormDur() const {return istdurMean;}
double tStorm::getMeanPrecip() const {return pMean;}

/*
**  GammaDev
**
**  Returns a random variable drawn from a Gamma distribution with parameter m.
**
**  (Note: not actually called; provided for future use).
*/
double tStorm::GammaDev(double m, long * idum)
{
  double x, y,z, c,t,b,u,w,v;

  if (m<1)
    {
      c = 1/m;
      t = 0.07 + 0.75*sqrt(1-m);
      b = 1 + exp(-t)*m/t;
      int accept = 0;
      while (accept == 0)
        {
          u = ran3(idum);
          w = ran3(idum);
          v = b *u;
          if (v<=1)
            {
              x  = t * pow(v, c);
              accept = ((w<=((2-x)/(2+x))) || (w<=exp(-x)));
            }
          else
            {
              x = -log(c*t*(b-v));
              y = x/t;
              accept = (((w*(m + y - m*y)) <= 1) || (w<= ( pow(y, (m-1)))));
            }
        }
    }
  else
    {
      b = m-1;
      c = 3*m - 0.75;
      int accept = 0;
      while (accept == 0)
        {
          u = ran3(idum); v = ran3(idum);
          w = u* ( 1-u);
          y = sqrt(c/w) * (u - 0.5);
          x = b + y;
          if ( x>= 0)
            {
              z = 64*( pow(w,3))*v*v;
              accept = (z <= ( 1 - 2*y*y/x)) || ( log(z) <= (2*(b*log(x/b) - y)));
            }
        }
    }
  return x;
}

<commit_msg>added option for sinusoidal variation in mean P, duration, spacing, and tested it<commit_after>/*
**  tStorm.cpp
**
**  Functions for tStorm objects.
**  A tStorm object generates random storms assuming an exponential
**  distribution of rainfall intensity, storm duration, and time to the
**  next storm. It is essentially an implementation of the model of
**  P. Eagleson, 1978b, Water Resources Research. Its services include
**  reading the necessary parameters from a tInputFile, generating a new
**  storm, and reporting its various values.
**    If you want to provide an option for NOT having storms vary
**  randomly, you can do so by setting optVariable to zero on initialization.
**    The GammaDev() function is provided for future reference; it is not
**  actually used in version 1.0.
**    tStorm objects could be easily modified (or inherited from) to use
**  different distributions. They can also be modified to create objects
**  for other random processes such as river flows, etc.
**    The random number generation routine ran3() from Numerical Recipes
**  is included in this file.
**
**  Version 1.0, Greg Tucker, November 1997.
**  $Id: tStorm.cpp,v 1.11 1998-07-15 22:25:41 gtucker Exp $
*/

#include <math.h>
#include "../Mathutil/mathutil.h"
#include "tStorm.h"

/*
**  tStorm::tStorm:  Constructor for storms. The default constructor
**                   assigns a value of unity to storm depth, duration,
**                   and interstorm duration. (Note:
**                   this constructor does not allow option for sinusoidal
**                   variation in means).
*/
tStorm::tStorm( int optvar )
{
   optVariable = optvar;
   optSinVar = 0;
   pMean = 1.0;
   stdurMean = 1.0;
   istdurMean = 1.0;
   p = 1.0;
   stdur = 1.0;
   istdur = 1.0;
   srand( 0 );
}

/*
**  tStorm::tStorm:  The constructor that's really used assigns values for
**                   mean storm depth, duration, and interstorm duration,
**                   initializes current depth, etc, to the mean values,
**                   and initializes the random number generator. (Note:
**                   this constructor does not allow option for sinusoidal
**                   variation in means).
*/
tStorm::tStorm( double mp, double ms, double mis, unsigned sd, int optvar )
{
   optVariable = optvar;
   optSinVar = 0;
   pMean = mp;
   stdurMean = ms;
   istdurMean = mis;
   p = pMean;
   stdur = stdurMean;
   istdur = istdurMean;
   seed = sd;
   srand( seed );
}

/*
**  tStorm::tStorm
**
**  Alternative constructor that reads parameters directly from a tInputFile
**  object. Reads option for variable storms (normally this is "yes"---that's
**  the point of these objects---but a user may wish to switch off variation
**  as a test), mean values for rainfall intensity, duration, and interstorm
**  period, and a random seed to initialize the random number generator.
**    Also reads an option for long-term sinusoidal variations in the mean
**  values, and if the option is selected, reads the relevant parameters.
**  Variables p0, stdur0, and istdur0 are the mean values of the means;
**  pdev, stdurdev, and istdurdev are the range of variation (e.g., if pMean
**  were to fluctuate between 5 and 10, p0 would be 7.5 and pdev 2.5).
*/
tStorm::tStorm( tInputFile &infile )
{
   // Read + set parameters for storm intensity, duration, and spacing
   optVariable = infile.ReadItem( optVariable, "OPTVAR" );
   pMean = infile.ReadItem( pMean, "PMEAN" );
   stdurMean = infile.ReadItem( stdurMean, "STDUR" );
   istdurMean = infile.ReadItem( istdurMean, "ISTDUR" );
   p = pMean;
   stdur = stdurMean;
   istdur = istdurMean;

   // Handle option for sinuidoil variation in means
   optSinVar = infile.ReadItem( optSinVar, "OPTSINVAR" );
   if( optSinVar )
   {
      p0 = pMean;
      stdur0 = stdurMean;
      istdur0 = istdurMean;
      twoPiLam = (2.0*PI)/(infile.ReadItem( twoPiLam, "PERIOD" ));
      pdev = infile.ReadItem( pdev, "MAXPMEAN" ) - pMean;
      if( pdev<0 ) cerr << "Warning: MAXPMEAN < PMEAN !";
      else if( pdev > pMean ) cerr << "Warning: MINPMEAN < 0 !";
      stdurdev = infile.ReadItem( stdurdev, "MAXSTDURMN" ) - stdurMean;
      if( stdurdev<0 ) cerr << "Warning: MAXSTDURMN < STDURMN !";
      else if( stdurdev > stdurMean ) cerr << "Warning: MINSTDURMN < 0 !";
      istdurdev = infile.ReadItem( istdurdev, "MAXISTDURMN" ) - istdurMean;
      if( istdurdev<0 ) cerr << "Warning: MAXISTDURMN < ISTDURMN !";
      else if( istdurdev > istdurMean ) cerr << "Warning: MINISTDURMN < 0 !";
   }

   // Read and initialize seed for random number generation
   seed = infile.ReadItem( seed, "SEED" );
   srand( seed );
}

/*
**  tStorm::GenerateStorm
**
**  Generates a new storm by drawing new values of p, stdur, and istdur from
**  an exponential distribution and updating the random seed.
**    If the minp parameter is greater than zero, the function will keep
**  picking storms until it finds one with p>minp. The total elapsed time,
**  including the rejected storms and their associated interstorm periods,
**  is stored istdur.
**
**  Parameters:  minp -- minimum value of rainfall rate p (default 0)
**               mind -- minimum storm depth to produce runoff (default 0)
**               tm -- current time in simulation
**  Members updated:  p, stdur, istdur take on new random values (if optVar)
**                    pMean, stdurMean, istdurMean adjusted (if optSinVar)
**  Assumptions:  pMean > 0
*/
void tStorm::GenerateStorm( double tm, double minp, double mind )
{
   // If option for sinusoidal variation is on, adjust the means
   // Also set values for current storm to the means, in case option for
   // random storms is off.
   if( optSinVar )
   {
      double sinfn = sin( tm*twoPiLam );
      pMean = p0 + pdev*sinfn;
      cout << "pMean = " << pMean << endl;
      stdurMean = stdur0 + stdurdev*sinfn;
      istdurMean = istdur0 + istdurdev*sinfn;
      p = pMean;
      stdur = stdurMean;
      istdur = istdurMean;
   }

   // If option for random storms is on, pick a storm at random.
   // Keep picking and accumulating time until the storm depth or intensity
   // is greater than the minimum value needed to produce runoff.
   if( optVariable )
   {
      stdur = 0;
      istdur = 0;
      do
      {
         p = pMean*ExpDev( &seed );
         istdur += istdurMean*ExpDev( &seed ) + stdur;
         stdur = stdurMean*ExpDev( &seed );
         /*cout << "P " << p << "  ST " << stdur << "  IST " << istdur
              << "  DP " << p*stdur << endl;*/
         srand( seed );
      } while( p<=minp && (p*stdur)<=mind );
   }
}

/*
**  tStorm::ExpDev:  Finds a random number with an exponential distribution
**                   (adapted from Numerical Recipes).
*/
double tStorm::ExpDev( long *idum )
{
    double dum;

    do
        dum = ran3( idum );
    while( dum==0.0 );
    return -log(dum);
}

/*
**  getStormDuration
**
**  Returns the storm duration.
*/
double tStorm::getStormDuration()
{
   return stdur;
}

/*
**  InterstormDur
**
**  Returns the interstorm duration.
*/
double tStorm::interstormDur()
{
   return istdur;
}

/*
**  getRainrate
**
**  Returns the rainfall rate.
*/
double tStorm::getRainrate()
{
   return p;
}

double tStorm::getMeanStormDur() const {return stdurMean;}
double tStorm::getMeanInterstormDur() const {return istdurMean;}
double tStorm::getMeanPrecip() const {return pMean;}

/*
**  GammaDev
**
**  Returns a random variable drawn from a Gamma distribution with parameter m.
**
**  (Note: not actually called; provided for future use).
*/
double tStorm::GammaDev(double m, long * idum)
{
  double x, y,z, c,t,b,u,w,v;

  if (m<1)
    {
      c = 1/m;
      t = 0.07 + 0.75*sqrt(1-m);
      b = 1 + exp(-t)*m/t;
      int accept = 0;
      while (accept == 0)
        {
          u = ran3(idum);
          w = ran3(idum);
          v = b *u;
          if (v<=1)
            {
              x  = t * pow(v, c);
              accept = ((w<=((2-x)/(2+x))) || (w<=exp(-x)));
            }
          else
            {
              x = -log(c*t*(b-v));
              y = x/t;
              accept = (((w*(m + y - m*y)) <= 1) || (w<= ( pow(y, (m-1)))));
            }
        }
    }
  else
    {
      b = m-1;
      c = 3*m - 0.75;
      int accept = 0;
      while (accept == 0)
        {
          u = ran3(idum); v = ran3(idum);
          w = u* ( 1-u);
          y = sqrt(c/w) * (u - 0.5);
          x = b + y;
          if ( x>= 0)
            {
              z = 64*( pow(w,3))*v*v;
              accept = (z <= ( 1 - 2*y*y/x)) || ( log(z) <= (2*(b*log(x/b) - y)));
            }
        }
    }
  return x;
}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

// Custom
#include "Utilities/IndirectPriorityQueue.h"

// Submodules
#include <Helpers/Helpers.h>

// Pixel descriptors
#include "PixelDescriptors/ImagePatchPixelDescriptor.h"

// Descriptor visitors
#include "Visitors/DescriptorVisitors/ImagePatchDescriptorVisitor.hpp"

// Inpainting visitors
#include "Visitors/InpaintingVisitor.hpp"
#include "Visitors/AcceptanceVisitors/DefaultAcceptanceVisitor.hpp"

// Nearest neighbors
#include "NearestNeighbor/LinearSearchBest/Property.hpp"

// Initializers
#include "Initializers/InitializeFromMaskImage.hpp"
#include "Initializers/InitializePriority.hpp"

// Inpainters
#include "Inpainters/CompositePatchInpainter.hpp"
#include "Inpainters/PatchInpainter.hpp"

// Difference functions
#include "DifferenceFunctions/ImagePatchDifference.hpp"
#include "DifferenceFunctions/SumAbsolutePixelDifference.hpp"
#include "DifferenceFunctions/SumSquaredPixelDifference.hpp"

// Utilities
#include "Utilities/PatchHelpers.h"

// Inpainting
#include "Algorithms/InpaintingAlgorithm.hpp"

// Priority
#include "Priority/PriorityCriminisi.h"

// ITK
#include "itkImageFileReader.h"

// Boost
#include <boost/graph/grid_graph.hpp>
#include <boost/property_map/property_map.hpp>

#include "Drivers/ClassicalImageInpainting.hpp"

// Run with: Data/trashcan.png Data/trashcan.mask 15 filled.png
int main(int argc, char *argv[])
{
  // Verify arguments
  if(argc != 5)
  {
    std::cerr << "Required arguments: image.png imageMask.mask patchHalfWidth output.png" << std::endl;
    std::cerr << "Input arguments: ";
    for(int i = 1; i < argc; ++i)
    {
      std::cerr << argv[i] << " ";
    }
    return EXIT_FAILURE;
  }

  // Parse arguments
  std::string imageFilename = argv[1];
  std::string maskFilename = argv[2];

  std::stringstream ssPatchHalfWidth;
  ssPatchHalfWidth << argv[3];
  unsigned int patchHalfWidth = 0;
  ssPatchHalfWidth >> patchHalfWidth;

  std::string outputFileName = argv[4];

  // Output arguments
//  std::cout << "Reading image: " << imageFilename << std::endl;
//  std::cout << "Reading mask: " << maskFilename << std::endl;
//  std::cout << "Patch half width: " << patchHalfWidth << std::endl;
//  std::cout << "Output: " << outputFileName << std::endl;

  typedef itk::Image<itk::CovariantVector<int, 3>, 2> OriginalImageType;

  typedef  itk::ImageFileReader<OriginalImageType> ImageReaderType;
  ImageReaderType::Pointer imageReader = ImageReaderType::New();
  imageReader->SetFileName(imageFilename);
  imageReader->Update();

//  OriginalImageType* originalImage = imageReader->GetOutput();

  OriginalImageType::Pointer originalImage = OriginalImageType::New();
  ITKHelpers::DeepCopy(imageReader->GetOutput(), originalImage.GetPointer());

  Mask::Pointer mask = Mask::New();
  mask->Read(maskFilename);

  ClassicalImageInpainting(originalImage, mask, patchHalfWidth);

  // If the output filename is a png file, then use the RGBImage writer so that it is first
  // casted to unsigned char. Otherwise, write the file directly.
  if(Helpers::GetFileExtension(outputFileName) == "png")
  {
    ITKHelpers::WriteRGBImage(originalImage.GetPointer(), outputFileName);
  }
  else
  {
    ITKHelpers::WriteImage(originalImage.GetPointer(), outputFileName);
  }

  return EXIT_SUCCESS;
}
<commit_msg>Use new directory structure.<commit_after>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

// Custom
#include "Utilities/IndirectPriorityQueue.h"

// Submodules
#include <Helpers/Helpers.h>

// Pixel descriptors
#include "PixelDescriptors/ImagePatchPixelDescriptor.h"

// Descriptor visitors
#include "Visitors/DescriptorVisitors/ImagePatchDescriptorVisitor.hpp"

// Inpainting visitors
#include "Visitors/InpaintingVisitors/InpaintingVisitor.hpp"
#include "Visitors/AcceptanceVisitors/DefaultAcceptanceVisitor.hpp"

// Nearest neighbors
#include "NearestNeighbor/LinearSearchBest/Property.hpp"

// Initializers
#include "Initializers/InitializeFromMaskImage.hpp"
#include "Initializers/InitializePriority.hpp"

// Inpainters
#include "Inpainters/CompositePatchInpainter.hpp"
#include "Inpainters/PatchInpainter.hpp"

// Difference functions
#include "DifferenceFunctions/Patch/ImagePatchDifference.hpp"
#include "DifferenceFunctions/Pixel/SumSquaredPixelDifference.hpp"

// Utilities
#include "Utilities/PatchHelpers.h"

// Inpainting
#include "Algorithms/InpaintingAlgorithm.hpp"

// Priority
#include "Priority/PriorityCriminisi.h"

// ITK
#include "itkImageFileReader.h"

// Boost
#include <boost/graph/grid_graph.hpp>
#include <boost/property_map/property_map.hpp>

#include "Drivers/ClassicalImageInpainting.hpp"

// Run with: Data/trashcan.png Data/trashcan.mask 15 filled.png
int main(int argc, char *argv[])
{
  // Verify arguments
  if(argc != 5)
  {
    std::cerr << "Required arguments: image.png imageMask.mask patchHalfWidth output.png" << std::endl;
    std::cerr << "Input arguments: ";
    for(int i = 1; i < argc; ++i)
    {
      std::cerr << argv[i] << " ";
    }
    return EXIT_FAILURE;
  }

  // Parse arguments
  std::string imageFilename = argv[1];
  std::string maskFilename = argv[2];

  std::stringstream ssPatchHalfWidth;
  ssPatchHalfWidth << argv[3];
  unsigned int patchHalfWidth = 0;
  ssPatchHalfWidth >> patchHalfWidth;

  std::string outputFileName = argv[4];

  // Output arguments
//  std::cout << "Reading image: " << imageFilename << std::endl;
//  std::cout << "Reading mask: " << maskFilename << std::endl;
//  std::cout << "Patch half width: " << patchHalfWidth << std::endl;
//  std::cout << "Output: " << outputFileName << std::endl;

  typedef itk::Image<itk::CovariantVector<int, 3>, 2> OriginalImageType;

  typedef  itk::ImageFileReader<OriginalImageType> ImageReaderType;
  ImageReaderType::Pointer imageReader = ImageReaderType::New();
  imageReader->SetFileName(imageFilename);
  imageReader->Update();

//  OriginalImageType* originalImage = imageReader->GetOutput();

  OriginalImageType::Pointer originalImage = OriginalImageType::New();
  ITKHelpers::DeepCopy(imageReader->GetOutput(), originalImage.GetPointer());

  Mask::Pointer mask = Mask::New();
  mask->Read(maskFilename);

  ClassicalImageInpainting(originalImage, mask, patchHalfWidth);

  // If the output filename is a png file, then use the RGBImage writer so that it is first
  // casted to unsigned char. Otherwise, write the file directly.
  if(Helpers::GetFileExtension(outputFileName) == "png")
  {
    ITKHelpers::WriteRGBImage(originalImage.GetPointer(), outputFileName);
  }
  else
  {
    ITKHelpers::WriteImage(originalImage.GetPointer(), outputFileName);
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//
//  JustInTime.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 28/07/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef JustInTime_h
#define JustInTime_h

#include "../Concurrency/AsyncTaskQueue.hpp"
#include "ClockingHintSource.hpp"
#include "ForceInline.hpp"

/*!
	A JustInTimeActor holds (i) an embedded object with a run_for method; and (ii) an amount
	of time since run_for was last called.

	Time can be added using the += operator. The -> operator can be used to access the
	embedded object. All time accumulated will be pushed to object before the pointer is returned.

	Machines that accumulate HalfCycle time but supply to a Cycle-counted device may supply a
	separate @c TargetTimeScale at template declaration.

	If the held object implements get_next_sequence_point() then it'll be used to flush implicitly
	as and when sequence points are hit. Callers can use will_flush() to predict these.

	If the held object is a subclass of ClockingHint::Source, this template will register as an
	observer and potentially stop clocking or stop delaying clocking until just-in-time references
	as directed.

	TODO: incorporate and codify AsyncJustInTimeActor.
*/
template <class T, class LocalTimeScale = HalfCycles, int multiplier = 1, int divider = 1> class JustInTimeActor:
	public ClockingHint::Observer {
	private:
		/*!
			A std::unique_ptr deleter which causes an update_sequence_point to occur on the actor supplied
			to it at construction if it implements get_next_sequence_point(). Otherwise destruction is a no-op.

			**Does not delete the object.**

			This is used by the -> operators below, which provide a unique pointer to the enclosed object and
			update their sequence points upon its destruction — i.e. after the caller has made whatever call
			or calls as were relevant to the enclosed object.
		*/
		class SequencePointAwareDeleter {
			public:
				explicit SequencePointAwareDeleter(JustInTimeActor<T, LocalTimeScale, multiplier, divider> *actor) noexcept
					: actor_(actor) {}

				forceinline void operator ()(const T *const) const {
					if constexpr (has_sequence_points<T>::value) {
						actor_->update_sequence_point();
					}
				}

			private:
				JustInTimeActor<T, LocalTimeScale, multiplier, divider> *const actor_;
		};

		// This block of SFINAE determines whether objects of type T accepts Cycles or HalfCycles.
		using HalfRunFor = void (T::*const)(HalfCycles);
		static uint8_t half_sig(...);
		static uint16_t half_sig(HalfRunFor);
		using TargetTimeScale =
			std::conditional_t<
				sizeof(half_sig(&T::run_for)) == sizeof(uint16_t),
				HalfCycles,
				Cycles>;

	public:
		/// Constructs a new JustInTimeActor using the same construction arguments as the included object.
		template<typename... Args> JustInTimeActor(Args&&... args) : object_(std::forward<Args>(args)...) {
			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				object_.set_clocking_hint_observer(this);
			}
		}

		/// Adds time to the actor.
		///
		/// @returns @c true if adding time caused a flush; @c false otherwise.
		forceinline bool operator += (LocalTimeScale rhs) {
			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				if(clocking_preference_ == ClockingHint::Preference::None) {
					return false;
				}
			}

			if constexpr (multiplier != 1) {
				time_since_update_ += rhs * multiplier;
			} else {
				time_since_update_ += rhs;
			}
			is_flushed_ = false;

			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				if (clocking_preference_ == ClockingHint::Preference::RealTime) {
					flush();
					return true;
				}
			}

			if constexpr (has_sequence_points<T>::value) {
				time_until_event_ -= rhs * multiplier;
				if(time_until_event_ <= LocalTimeScale(0)) {
					time_overrun_ = time_until_event_ / divider;
					flush();
					update_sequence_point();
					return true;
				}
			}

			return false;
		}

		/// Flushes all accumulated time and returns a pointer to the included object.
		///
		/// If this object provides sequence points, checks for changes to the next
		/// sequence point upon deletion of the pointer.
		[[nodiscard]] forceinline auto operator->() {
			flush();
			return std::unique_ptr<T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(this));
		}

		/// Acts exactly as per the standard ->, but preserves constness.
		///
		/// Despite being const, this will flush the object and, if relevant, update the next sequence point.
		[[nodiscard]] forceinline auto operator -> () const {
			auto non_const_this = const_cast<JustInTimeActor<T, LocalTimeScale, multiplier, divider> *>(this);
			non_const_this->flush();
			return std::unique_ptr<const T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(non_const_this));
		}

		/// @returns a pointer to the included object, without flushing time.
		[[nodiscard]] forceinline T *last_valid() {
			return &object_;
		}

		/// @returns a const pointer to the included object, without flushing time.
		[[nodiscard]] forceinline const T *last_valid() const {
			return &object_;
		}

		/// @returns the amount of time since the object was last flushed, in the target time scale.
		[[nodiscard]] forceinline TargetTimeScale time_since_flush() const {
			if constexpr (divider == 1) {
				return time_since_update_;
			}
			return TargetTimeScale(time_since_update_.as_integral() / divider);
		}

		/// @returns the amount of time since the object was last flushed, plus the local time scale @c offset,
		/// converted to the target time scale.
		[[nodiscard]] forceinline TargetTimeScale time_since_flush(LocalTimeScale offset) const {
			if constexpr (divider == 1) {
				return time_since_update_ + offset;
			}
			return TargetTimeScale((time_since_update_ + offset).as_integral() / divider);
		}

		/// Flushes all accumulated time.
		///
		/// This does not affect this actor's record of when the next sequence point will occur.
		forceinline void flush() {
			if(!is_flushed_) {
				did_flush_ = is_flushed_ = true;
				if constexpr (divider == 1) {
					const auto duration = time_since_update_.template flush<TargetTimeScale>();
					object_.run_for(duration);
				} else {
					const auto duration = time_since_update_.template divide<TargetTimeScale>(LocalTimeScale(divider));
					if(duration > TargetTimeScale(0))
						object_.run_for(duration);
				}
			}
		}

		/// Indicates whether a flush has occurred since the last call to did_flush().
		[[nodiscard]] forceinline bool did_flush() {
			const bool did_flush = did_flush_;
			did_flush_ = false;
			return did_flush;
		}

		/// @returns a number in the range [-max, 0] indicating the offset of the most recent sequence
		/// point from the final time at the end of the += that triggered the sequence point.
		[[nodiscard]] forceinline LocalTimeScale last_sequence_point_overrun() {
			return time_overrun_;
		}

		/// @returns the number of cycles until the next sequence-point-based flush, if the embedded object
		/// supports sequence points; @c LocalTimeScale() otherwise.
		[[nodiscard]] LocalTimeScale cycles_until_implicit_flush() const {
			return time_until_event_ / divider;
		}

		/// Indicates whether a sequence-point-caused flush will occur if the specified period is added.
		[[nodiscard]] forceinline bool will_flush(LocalTimeScale rhs) const {
			if constexpr (!has_sequence_points<T>::value) {
				return false;
			}
			return rhs >= time_until_event_;
		}

		/// Indicates the amount of time, in the local time scale, until the first local slot that falls wholly
		/// after @c duration, if that delay were to occur in @c offset units of time from now.
		[[nodiscard]] forceinline LocalTimeScale back_map(TargetTimeScale duration, TargetTimeScale offset) const {
			// A 1:1 mapping is easy.
			if constexpr (multiplier == 1 && divider == 1) {
				return duration;
			}

			// Work out when this query is placed, and the time to which it relates
			const auto base = time_since_update_ + offset * divider;
			const auto target = base + duration * divider;

			// Figure out the number of whole input steps that is required to get
			// past target, and subtract the number of whole input steps necessary
			// to get to base.
			const auto steps_to_base = base.as_integral() / divider;
			const auto steps_to_target = (target.as_integral() + divider - 1) / divider;

			return LocalTimeScale(steps_to_target - steps_to_base);
		}

		/// Updates this template's record of the next sequence point.
		void update_sequence_point() {
			if constexpr (has_sequence_points<T>::value) {
				time_until_event_ = object_.get_next_sequence_point() * divider;
				assert(time_until_event_ > LocalTimeScale(0));
			}
		}

		/// @returns A cached copy of the object's clocking preference.
		ClockingHint::Preference clocking_preference() const {
			return clocking_preference_;
		}

	private:
		T object_;
		LocalTimeScale time_since_update_, time_until_event_, time_overrun_;
		bool is_flushed_ = true;
		bool did_flush_ = false;

		template <typename S, typename = void> struct has_sequence_points : std::false_type {};
		template <typename S> struct has_sequence_points<S, decltype(void(std::declval<S &>().get_next_sequence_point()))> : std::true_type {};

		ClockingHint::Preference clocking_preference_ = ClockingHint::Preference::JustInTime;
		void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference clocking) {
			clocking_preference_ = clocking;
		}
};

/*!
	An AsyncJustInTimeActor acts like a JustInTimeActor but additionally contains an AsyncTaskQueue.
	Any time the amount of accumulated time crosses a threshold provided at construction time,
	the object will be updated on the AsyncTaskQueue.
*/
template <class T, class LocalTimeScale = HalfCycles, class TargetTimeScale = LocalTimeScale> class AsyncJustInTimeActor {
	public:
		/// Constructs a new AsyncJustInTimeActor using the same construction arguments as the included object.
		template<typename... Args> AsyncJustInTimeActor(TargetTimeScale threshold, Args&&... args) :
			object_(std::forward<Args>(args)...),
		 	threshold_(threshold) {}

		/// Adds time to the actor.
		inline void operator += (const LocalTimeScale &rhs) {
			time_since_update_ += rhs;
			if(time_since_update_ >= threshold_) {
				time_since_update_ -= threshold_;
				task_queue_.enqueue([this] () {
					object_.run_for(threshold_);
				});
			}
			is_flushed_ = false;
		}

		/// Flushes all accumulated time and returns a pointer to the included object.
		inline T *operator->() {
			flush();
			return &object_;
		}

		/// Returns a pointer to the included object without flushing time.
		inline T *last_valid() {
			return &object_;
		}

		/// Flushes all accumulated time.
		inline void flush() {
			if(!is_flushed_) {
				task_queue_.flush();
				object_.run_for(time_since_update_.template flush<TargetTimeScale>());
				is_flushed_ = true;
			}
		}

	private:
		T object_;
		LocalTimeScale time_since_update_;
		TargetTimeScale threshold_;
		bool is_flushed_ = true;
		Concurrency::AsyncTaskQueue task_queue_;
};

#endif /* JustInTime_h */
<commit_msg>Correct divisor.<commit_after>//
//  JustInTime.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 28/07/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef JustInTime_h
#define JustInTime_h

#include "../Concurrency/AsyncTaskQueue.hpp"
#include "ClockingHintSource.hpp"
#include "ForceInline.hpp"

/*!
	A JustInTimeActor holds (i) an embedded object with a run_for method; and (ii) an amount
	of time since run_for was last called.

	Time can be added using the += operator. The -> operator can be used to access the
	embedded object. All time accumulated will be pushed to object before the pointer is returned.

	Machines that accumulate HalfCycle time but supply to a Cycle-counted device may supply a
	separate @c TargetTimeScale at template declaration.

	If the held object implements get_next_sequence_point() then it'll be used to flush implicitly
	as and when sequence points are hit. Callers can use will_flush() to predict these.

	If the held object is a subclass of ClockingHint::Source, this template will register as an
	observer and potentially stop clocking or stop delaying clocking until just-in-time references
	as directed.

	TODO: incorporate and codify AsyncJustInTimeActor.
*/
template <class T, class LocalTimeScale = HalfCycles, int multiplier = 1, int divider = 1> class JustInTimeActor:
	public ClockingHint::Observer {
	private:
		/*!
			A std::unique_ptr deleter which causes an update_sequence_point to occur on the actor supplied
			to it at construction if it implements get_next_sequence_point(). Otherwise destruction is a no-op.

			**Does not delete the object.**

			This is used by the -> operators below, which provide a unique pointer to the enclosed object and
			update their sequence points upon its destruction — i.e. after the caller has made whatever call
			or calls as were relevant to the enclosed object.
		*/
		class SequencePointAwareDeleter {
			public:
				explicit SequencePointAwareDeleter(JustInTimeActor<T, LocalTimeScale, multiplier, divider> *actor) noexcept
					: actor_(actor) {}

				forceinline void operator ()(const T *const) const {
					if constexpr (has_sequence_points<T>::value) {
						actor_->update_sequence_point();
					}
				}

			private:
				JustInTimeActor<T, LocalTimeScale, multiplier, divider> *const actor_;
		};

		// This block of SFINAE determines whether objects of type T accepts Cycles or HalfCycles.
		using HalfRunFor = void (T::*const)(HalfCycles);
		static uint8_t half_sig(...);
		static uint16_t half_sig(HalfRunFor);
		using TargetTimeScale =
			std::conditional_t<
				sizeof(half_sig(&T::run_for)) == sizeof(uint16_t),
				HalfCycles,
				Cycles>;

	public:
		/// Constructs a new JustInTimeActor using the same construction arguments as the included object.
		template<typename... Args> JustInTimeActor(Args&&... args) : object_(std::forward<Args>(args)...) {
			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				object_.set_clocking_hint_observer(this);
			}
		}

		/// Adds time to the actor.
		///
		/// @returns @c true if adding time caused a flush; @c false otherwise.
		forceinline bool operator += (LocalTimeScale rhs) {
			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				if(clocking_preference_ == ClockingHint::Preference::None) {
					return false;
				}
			}

			if constexpr (multiplier != 1) {
				time_since_update_ += rhs * multiplier;
			} else {
				time_since_update_ += rhs;
			}
			is_flushed_ = false;

			if constexpr (std::is_base_of<ClockingHint::Source, T>::value) {
				if (clocking_preference_ == ClockingHint::Preference::RealTime) {
					flush();
					return true;
				}
			}

			if constexpr (has_sequence_points<T>::value) {
				time_until_event_ -= rhs * multiplier;
				if(time_until_event_ <= LocalTimeScale(0)) {
					time_overrun_ = time_until_event_ / divider;
					flush();
					update_sequence_point();
					return true;
				}
			}

			return false;
		}

		/// Flushes all accumulated time and returns a pointer to the included object.
		///
		/// If this object provides sequence points, checks for changes to the next
		/// sequence point upon deletion of the pointer.
		[[nodiscard]] forceinline auto operator->() {
			flush();
			return std::unique_ptr<T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(this));
		}

		/// Acts exactly as per the standard ->, but preserves constness.
		///
		/// Despite being const, this will flush the object and, if relevant, update the next sequence point.
		[[nodiscard]] forceinline auto operator -> () const {
			auto non_const_this = const_cast<JustInTimeActor<T, LocalTimeScale, multiplier, divider> *>(this);
			non_const_this->flush();
			return std::unique_ptr<const T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(non_const_this));
		}

		/// @returns a pointer to the included object, without flushing time.
		[[nodiscard]] forceinline T *last_valid() {
			return &object_;
		}

		/// @returns a const pointer to the included object, without flushing time.
		[[nodiscard]] forceinline const T *last_valid() const {
			return &object_;
		}

		/// @returns the amount of time since the object was last flushed, in the target time scale.
		[[nodiscard]] forceinline TargetTimeScale time_since_flush() const {
			if constexpr (divider == 1) {
				return time_since_update_;
			}
			return TargetTimeScale(time_since_update_.as_integral() / divider);
		}

		/// @returns the amount of time since the object was last flushed, plus the local time scale @c offset,
		/// converted to the target time scale.
		[[nodiscard]] forceinline TargetTimeScale time_since_flush(LocalTimeScale offset) const {
			if constexpr (divider == 1) {
				return time_since_update_ + offset;
			}
			return TargetTimeScale((time_since_update_ + offset).as_integral() / divider);
		}

		/// Flushes all accumulated time.
		///
		/// This does not affect this actor's record of when the next sequence point will occur.
		forceinline void flush() {
			if(!is_flushed_) {
				did_flush_ = is_flushed_ = true;
				if constexpr (divider == 1) {
					const auto duration = time_since_update_.template flush<TargetTimeScale>();
					object_.run_for(duration);
				} else {
					const auto duration = time_since_update_.template divide<TargetTimeScale>(LocalTimeScale(divider));
					if(duration > TargetTimeScale(0))
						object_.run_for(duration);
				}
			}
		}

		/// Indicates whether a flush has occurred since the last call to did_flush().
		[[nodiscard]] forceinline bool did_flush() {
			const bool did_flush = did_flush_;
			did_flush_ = false;
			return did_flush;
		}

		/// @returns a number in the range [-max, 0] indicating the offset of the most recent sequence
		/// point from the final time at the end of the += that triggered the sequence point.
		[[nodiscard]] forceinline LocalTimeScale last_sequence_point_overrun() {
			return time_overrun_;
		}

		/// @returns the number of cycles until the next sequence-point-based flush, if the embedded object
		/// supports sequence points; @c LocalTimeScale() otherwise.
		[[nodiscard]] LocalTimeScale cycles_until_implicit_flush() const {
			return time_until_event_ / divider;
		}

		/// Indicates whether a sequence-point-caused flush will occur if the specified period is added.
		[[nodiscard]] forceinline bool will_flush(LocalTimeScale rhs) const {
			if constexpr (!has_sequence_points<T>::value) {
				return false;
			}
			return rhs >= time_until_event_;
		}

		/// Indicates the amount of time, in the local time scale, until the first local slot that falls wholly
		/// after @c duration, if that delay were to occur in @c offset units of time from now.
		[[nodiscard]] forceinline LocalTimeScale back_map(TargetTimeScale duration, TargetTimeScale offset) const {
			// A 1:1 mapping is easy.
			if constexpr (multiplier == 1 && divider == 1) {
				return duration;
			}

			// Work out when this query is placed, and the time to which it relates
			const auto base = time_since_update_ + offset * divider;
			const auto target = base + duration * divider;

			// Figure out the number of whole input steps that is required to get
			// past target, and subtract the number of whole input steps necessary
			// to get to base.
			const auto steps_to_base = base.as_integral() / multiplier;
			const auto steps_to_target = (target.as_integral() + divider - 1) / multiplier;

			return LocalTimeScale(steps_to_target - steps_to_base);
		}

		/// Updates this template's record of the next sequence point.
		void update_sequence_point() {
			if constexpr (has_sequence_points<T>::value) {
				time_until_event_ = object_.get_next_sequence_point() * divider;
				assert(time_until_event_ > LocalTimeScale(0));
			}
		}

		/// @returns A cached copy of the object's clocking preference.
		ClockingHint::Preference clocking_preference() const {
			return clocking_preference_;
		}

	private:
		T object_;
		LocalTimeScale time_since_update_, time_until_event_, time_overrun_;
		bool is_flushed_ = true;
		bool did_flush_ = false;

		template <typename S, typename = void> struct has_sequence_points : std::false_type {};
		template <typename S> struct has_sequence_points<S, decltype(void(std::declval<S &>().get_next_sequence_point()))> : std::true_type {};

		ClockingHint::Preference clocking_preference_ = ClockingHint::Preference::JustInTime;
		void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference clocking) {
			clocking_preference_ = clocking;
		}
};

/*!
	An AsyncJustInTimeActor acts like a JustInTimeActor but additionally contains an AsyncTaskQueue.
	Any time the amount of accumulated time crosses a threshold provided at construction time,
	the object will be updated on the AsyncTaskQueue.
*/
template <class T, class LocalTimeScale = HalfCycles, class TargetTimeScale = LocalTimeScale> class AsyncJustInTimeActor {
	public:
		/// Constructs a new AsyncJustInTimeActor using the same construction arguments as the included object.
		template<typename... Args> AsyncJustInTimeActor(TargetTimeScale threshold, Args&&... args) :
			object_(std::forward<Args>(args)...),
		 	threshold_(threshold) {}

		/// Adds time to the actor.
		inline void operator += (const LocalTimeScale &rhs) {
			time_since_update_ += rhs;
			if(time_since_update_ >= threshold_) {
				time_since_update_ -= threshold_;
				task_queue_.enqueue([this] () {
					object_.run_for(threshold_);
				});
			}
			is_flushed_ = false;
		}

		/// Flushes all accumulated time and returns a pointer to the included object.
		inline T *operator->() {
			flush();
			return &object_;
		}

		/// Returns a pointer to the included object without flushing time.
		inline T *last_valid() {
			return &object_;
		}

		/// Flushes all accumulated time.
		inline void flush() {
			if(!is_flushed_) {
				task_queue_.flush();
				object_.run_for(time_since_update_.template flush<TargetTimeScale>());
				is_flushed_ = true;
			}
		}

	private:
		T object_;
		LocalTimeScale time_since_update_;
		TargetTimeScale threshold_;
		bool is_flushed_ = true;
		Concurrency::AsyncTaskQueue task_queue_;
};

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


<commit_before>#include "pch.hpp"
#include "Texture.hpp"
#include <DirectXTex.h>
#include <wchar.h>
#include <d3d11.h>

namespace dx
{
    wrl::ComPtr<ID3D11Texture2D> MakeTexture2D(ID3D11Device& device, const DirectX::ScratchImage& image,
        const DirectX::TexMetadata& metaData, ResourceUsage usage)
    {
        wrl::ComPtr<ID3D11Resource> resource;
        TryHR(DirectX::CreateTextureEx(&device, image.GetImages(), image.GetImageCount(), metaData, static_cast<D3D11_USAGE>(usage), D3D11_BIND_SHADER_RESOURCE, 0, 0, 0, resource.ReleaseAndGetAddressOf()));
        wrl::ComPtr<ID3D11Texture2D> texture;
        const auto hr = resource.As(&texture);
        if (hr == E_NOINTERFACE)
            throw std::runtime_error{ "Invalid 2D WIC image" };
        TryHR(hr);
        return texture;
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromWicFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromWICFile(filePath.c_str(),
            DirectX::WIC_FLAGS_NONE, &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromTgaFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromTGAFile(filePath.c_str(), &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromDdsFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage, std::uint32_t ddsFlags)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromDDSFile(filePath.c_str(), ddsFlags, &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromMemory(ID3D11Device& device, const unsigned char* buffer, std::uint32_t width, std::uint32_t height, ResourceUsage usage)
    {
        D3D11_TEXTURE2D_DESC textureDesc = {};
        textureDesc.Width = width;
        textureDesc.Height = height;
        textureDesc.MipLevels = 1;
        textureDesc.ArraySize = 1;
        textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        textureDesc.SampleDesc.Count = 1;
        textureDesc.SampleDesc.Quality = 0;
        textureDesc.Usage = static_cast<D3D11_USAGE>(usage);
        textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        textureDesc.CPUAccessFlags = 0;
        textureDesc.MiscFlags = 0;

        wrl::ComPtr<ID3D11Texture2D> d3dTexture;
        D3D11_SUBRESOURCE_DATA data = {};
        data.pSysMem = buffer;
        data.SysMemPitch = width * 4;
        data.SysMemSlicePitch = width * height * 4;
        TryHR(device.CreateTexture2D(&textureDesc, &data, d3dTexture.ReleaseAndGetAddressOf()));

        return d3dTexture;
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        const auto format = filePath.extension();
        if (format == L".tga")
        {
            return Load2DTexFromTgaFile(device, filePath, usage);
        }
        else if (format == L".dds")
        {
            return Load2DTexFromDdsFile(device, filePath, usage, DirectX::DDS_FLAGS_NONE);
        }
        else
        {
            return Load2DTexFromWicFile(device, filePath, usage);
        }
    }

    wrl::ComPtr<ID3D11ShaderResourceView> Get2DTexView(ID3D11Device& device, ID3D11Texture2D& texture)
    {
        D3D11_SHADER_RESOURCE_VIEW_DESC desc = {};
        D3D11_TEXTURE2D_DESC textureDesc = {};
        texture.GetDesc(&textureDesc);
        desc.Format = textureDesc.Format;
        desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        desc.Texture2D = { 0, textureDesc.MipLevels };
        wrl::ComPtr<ID3D11ShaderResourceView> view;
        TryHR(device.CreateShaderResourceView(&texture, &desc, view.ReleaseAndGetAddressOf()));
        return view;
    }
}

extern wchar_t _CONST_RETURN* __CRTDECL wmemchr(
    _In_reads_(_N) wchar_t const* _S,
    _In_           wchar_t        _C,
    _In_           size_t         _N);<commit_msg>Remove the dirty hack for clang-cl.<commit_after>#include "pch.hpp"
#include "Texture.hpp"
#include <DirectXTex.h>
#include <wchar.h>
#include <d3d11.h>

namespace dx
{
    wrl::ComPtr<ID3D11Texture2D> MakeTexture2D(ID3D11Device& device, const DirectX::ScratchImage& image,
        const DirectX::TexMetadata& metaData, ResourceUsage usage)
    {
        wrl::ComPtr<ID3D11Resource> resource;
        TryHR(DirectX::CreateTextureEx(&device, image.GetImages(), image.GetImageCount(), metaData, static_cast<D3D11_USAGE>(usage), D3D11_BIND_SHADER_RESOURCE, 0, 0, 0, resource.ReleaseAndGetAddressOf()));
        wrl::ComPtr<ID3D11Texture2D> texture;
        const auto hr = resource.As(&texture);
        if (hr == E_NOINTERFACE)
            throw std::runtime_error{ "Invalid 2D WIC image" };
        TryHR(hr);
        return texture;
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromWicFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromWICFile(filePath.c_str(),
            DirectX::WIC_FLAGS_NONE, &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromTgaFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromTGAFile(filePath.c_str(), &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromDdsFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage, std::uint32_t ddsFlags)
    {
        DirectX::ScratchImage image;
        DirectX::TexMetadata metaData;
        TryHR(DirectX::LoadFromDDSFile(filePath.c_str(), ddsFlags, &metaData, image));
        return MakeTexture2D(device, image, metaData, usage);
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromMemory(ID3D11Device& device, const unsigned char* buffer, std::uint32_t width, std::uint32_t height, ResourceUsage usage)
    {
        D3D11_TEXTURE2D_DESC textureDesc = {};
        textureDesc.Width = width;
        textureDesc.Height = height;
        textureDesc.MipLevels = 1;
        textureDesc.ArraySize = 1;
        textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        textureDesc.SampleDesc.Count = 1;
        textureDesc.SampleDesc.Quality = 0;
        textureDesc.Usage = static_cast<D3D11_USAGE>(usage);
        textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        textureDesc.CPUAccessFlags = 0;
        textureDesc.MiscFlags = 0;

        wrl::ComPtr<ID3D11Texture2D> d3dTexture;
        D3D11_SUBRESOURCE_DATA data = {};
        data.pSysMem = buffer;
        data.SysMemPitch = width * 4;
        data.SysMemSlicePitch = width * height * 4;
        TryHR(device.CreateTexture2D(&textureDesc, &data, d3dTexture.ReleaseAndGetAddressOf()));

        return d3dTexture;
    }

    wrl::ComPtr<ID3D11Texture2D> Load2DTexFromFile(ID3D11Device& device, const fs::path& filePath, ResourceUsage usage)
    {
        const auto format = filePath.extension();
        if (format == L".tga")
        {
            return Load2DTexFromTgaFile(device, filePath, usage);
        }
        else if (format == L".dds")
        {
            return Load2DTexFromDdsFile(device, filePath, usage, DirectX::DDS_FLAGS_NONE);
        }
        else
        {
            return Load2DTexFromWicFile(device, filePath, usage);
        }
    }

    wrl::ComPtr<ID3D11ShaderResourceView> Get2DTexView(ID3D11Device& device, ID3D11Texture2D& texture)
    {
        D3D11_SHADER_RESOURCE_VIEW_DESC desc = {};
        D3D11_TEXTURE2D_DESC textureDesc = {};
        texture.GetDesc(&textureDesc);
        desc.Format = textureDesc.Format;
        desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        desc.Texture2D = { 0, textureDesc.MipLevels };
        wrl::ComPtr<ID3D11ShaderResourceView> view;
        TryHR(device.CreateShaderResourceView(&texture, &desc, view.ReleaseAndGetAddressOf()));
        return view;
    }
}<|endoftext|>


<commit_before>//  Powiter
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
//  Created by Frédéric Devernay on 03/09/13.
//
//

#include "OfxHost.h"

#include <cassert>
#include <fstream>
#include <QtCore/QDir>
#if QT_VERSION < 0x050000
#include <QtGui/QDesktopServices>
#else
#include <QStandardPaths>
#endif

#include <ofxhPluginAPICache.h>
#include <ofxhImageEffect.h>
#include <ofxhImageEffectAPI.h>
#include <ofxhHost.h>

#include "Engine/OfxNode.h"
#include "Engine/OfxImageEffectInstance.h"

using namespace Powiter;

Powiter::OfxHost::OfxHost()
:_imageEffectPluginCache(*this)
{
    _properties.setStringProperty(kOfxPropName, POWITER_APPLICATION_NAME "Host");
    _properties.setStringProperty(kOfxPropLabel, POWITER_APPLICATION_NAME);
    _properties.setIntProperty(kOfxImageEffectHostPropIsBackground, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsOverlays, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultiResolution, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsTiles, 1);
    _properties.setIntProperty(kOfxImageEffectPropTemporalClipAccess, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentRGBA, 0);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentAlpha, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, 0 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, 2 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, 3 );

    _properties.setStringProperty(kOfxImageEffectPropSupportedPixelDepths,kOfxBitDepthFloat,0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFrameRate, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFielding, 0);
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomInteract, 1 );
    _properties.setIntProperty(kOfxParamHostPropSupportsStringAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsChoiceAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsBooleanAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropMaxParameters, -1);
    _properties.setIntProperty(kOfxParamHostPropMaxPages, 0);
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 0 );
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 1 );

}

Powiter::OfxHost::~OfxHost()
{
    writeOFXCache();
}

OFX::Host::ImageEffect::Instance* Powiter::OfxHost::newInstance(void* ,
                                                     OFX::Host::ImageEffect::ImageEffectPlugin* plugin,
                                                     OFX::Host::ImageEffect::Descriptor& desc,
                                                     const std::string& context)
{
    assert(plugin);

    return new Powiter::OfxImageEffectInstance(plugin,desc,context,false);
}

/// Override this to create a descriptor, this makes the 'root' descriptor
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(OFX::Host::ImageEffect::ImageEffectPlugin* plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(plugin);
    return desc;
}

/// used to construct a context description, rootContext is the main context
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext,
                                                          OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(rootContext, plugin);
    return desc;
}

/// used to construct populate the cache
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(const std::string &bundlePath,
                                                          OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(bundlePath, plugin);
    return desc;
}

/// message
OfxStatus Powiter::OfxHost::vmessage(const char* type,
                          const char* ,
                          const char* format,
                          va_list args)
{
    assert(type);
    assert(format);
    bool isQuestion = false;
    const char *prefix = "Message : ";
    if (strcmp(type, kOfxMessageLog) == 0) {
        prefix = "Log : ";
    }
    else if(strcmp(type, kOfxMessageFatal) == 0 ||
            strcmp(type, kOfxMessageError) == 0) {
        prefix = "Error : ";
    }
    else if(strcmp(type, kOfxMessageQuestion) == 0)  {
        prefix = "Question : ";
        isQuestion = true;
    }

    // Just dump our message to stdout, should be done with a proper
    // UI in a full ap, and post a dialogue for yes/no questions.
    fputs(prefix, stdout);
    vprintf(format, args);
    printf("\n");

    if(isQuestion) {
        /// cant do this properly inour example, as we need to raise a dialogue to ask a question, so just return yes
        return kOfxStatReplyYes;
    }
    else {
        return kOfxStatOK;
    }
}

OfxNode* Powiter::OfxHost::createOfxNode(const std::string& name,AppInstance* app) {
    OfxStatus stat;
    OFXPluginsIterator ofxPlugin = _ofxPlugins.find(name);
    if (ofxPlugin == _ofxPlugins.end()) {
        return NULL;
    }
    OFX::Host::ImageEffect::ImageEffectPlugin* plugin = _imageEffectPluginCache.getPluginById(ofxPlugin->second.first);
    if (!plugin) {
        return NULL;
    }
    const std::set<std::string>& contexts = plugin->getContexts();
    std::string context;

    if (contexts.size() == 1) {
        context = (*contexts.begin());
    }else{
        std::set<std::string>::iterator found = contexts.find(kOfxImageEffectContextGeneral);
        if(found != contexts.end()){
            context = *found;
        }else{
            found = contexts.find(kOfxImageEffectContextFilter);
            if(found != contexts.end()){
                context = *found;
            }else{
                found = contexts.find(kOfxImageEffectContextGenerator);
                if(found != contexts.end()){
                    context = *found;
                }else{
                    found = contexts.find(kOfxImageEffectContextTransition);
                    if(found != contexts.end()){
                        context = *found;
                    }else{
                        context = kOfxImageEffectContextPaint;
                    }
                }
            }
        }

    }

    bool rval = false;
    try{
        rval = plugin->getPluginHandle();
    } catch (const std::exception &e) {
        std::cout << "Error: Could not get plugin handle for plugin \"" << name << "\":" << e.what() << std::endl;
    }
    if(!rval) {
        return NULL;
    }
    OfxNode* node = new OfxNode(app,plugin,context);
    assert(node);
    Powiter::OfxImageEffectInstance* effect = node->effectInstance();
    if (effect) {
        stat = effect->createInstanceAction();
        assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault);
    } else {
        std::cout << "Error: Could not create effect instance for plugin \"" << name << "\"" << std::endl;
        delete node;
        return NULL;
    }

    /*must be called AFTER createInstanceAction!*/
    node->tryInitializeOverlayInteracts();
    return node;
}

QStringList Powiter::OfxHost::loadOFXPlugins() {
    QStringList pluginNames;

    assert(OFX::Host::PluginCache::getPluginCache());
    /// set the version label in the global cache
    OFX::Host::PluginCache::getPluginCache()->setCacheVersion(POWITER_APPLICATION_NAME "OFXCachev1");

    /// make an image effect plugin cache

    /// register the image effect cache with the global plugin cache
    _imageEffectPluginCache.registerInCache(*OFX::Host::PluginCache::getPluginCache());

#if defined(WINDOWS)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("C:\\Program Files\\Common Files\\OFX\\Nuke");
#endif
#if defined(__linux__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/usr/OFX/Nuke");
#endif
#if defined(__APPLE__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/Library/OFX/Nuke");
#endif

    /// now read an old cache
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation) + QDir::separator() + "OFXCache.xml";
#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QDir::separator() + "OFXCache.xml";
#endif
    std::ifstream ifs(ofxcachename.toStdString().c_str());
    if (ifs.is_open()) {
        OFX::Host::PluginCache::getPluginCache()->readCache(ifs);
        ifs.close();
    }
    OFX::Host::PluginCache::getPluginCache()->scanPluginFiles();

    /*Filling node name list and plugin grouping*/
    const std::vector<OFX::Host::ImageEffect::ImageEffectPlugin *>& plugins = _imageEffectPluginCache.getPlugins();
    for (unsigned int i = 0 ; i < plugins.size(); ++i) {
        OFX::Host::ImageEffect::ImageEffectPlugin* p = plugins[i];
        assert(p);
        if(p->getContexts().size() == 0)
            continue;
        QString name = p->getDescriptor().getLabel().c_str();
        if(name.isEmpty()){
            name = p->getDescriptor().getShortLabel().c_str();
        }

        if(name.isEmpty()){
            name = p->getDescriptor().getLongLabel().c_str();
        }

        QString rawName = name;
        QString id = p->getIdentifier().c_str();
        QString grouping = p->getDescriptor().getPluginGrouping().c_str();

        int pluginCount = p->getBinary()->getNPlugins();
        QString bundlePath;
        bundlePath = pluginCount > 1 ? p->getBinary()->getBundlePath().c_str() : "";
        QStringList groups = ofxExtractAllPartsOfGrouping(grouping,bundlePath);
        if (groups.size() >= 1) {
            name.append("  [");
            name.append(groups[0]);
            name.append("]");
        }
        assert(p->getBinary());
        QString iconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
        iconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
        iconFilename.append(id);
        iconFilename.append(".png");
        QString groupIconFilename;
        if (groups.size() >= 1) {
            groupIconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
            groupIconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
            groupIconFilename.append(groups[0]);
//            if(bundlePath.size() > 0 && pluginCount > 1 && groups.size() > 1){
//                groupIconFilename.append('/');
//                groupIconFilename.append(groups[1]);
//            }
            groupIconFilename.append(".png");
        }
        emit toolButtonAdded(groups, rawName, iconFilename, groupIconFilename);
        _ofxPlugins.insert(make_pair(name.toStdString(), make_pair(id.toStdString(), grouping.toStdString())));
        pluginNames.append(name);
    }
    return pluginNames;
}

void Powiter::OfxHost::writeOFXCache(){
    /// and write a new cache, long version with everything in there
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);

#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
#endif
    QDir().mkpath(ofxcachename);
    ofxcachename +=  QDir::separator();
    ofxcachename += "OFXCache.xml";
    std::ofstream of(ofxcachename.toStdString().c_str());
    assert(of.is_open());
    assert(OFX::Host::PluginCache::getPluginCache());
    OFX::Host::PluginCache::getPluginCache()->writePluginCache(of);
    of.close();
    //Clean up, to be polite.
    OFX::Host::PluginCache::clearPluginCache();
}

<commit_msg>Fixed conflicts<commit_after>//  Powiter
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
//  Created by Frédéric Devernay on 03/09/13.
//
//

#include "OfxHost.h"

#include <cassert>
#include <fstream>
#include <QtCore/QDir>
#if QT_VERSION < 0x050000
#include <QtGui/QDesktopServices>
#else
#include <QStandardPaths>
#endif

#include <ofxhPluginAPICache.h>
#include <ofxhImageEffect.h>
#include <ofxhImageEffectAPI.h>
#include <ofxhHost.h>

#include "Engine/OfxNode.h"
#include "Engine/OfxImageEffectInstance.h"

using namespace Powiter;

Powiter::OfxHost::OfxHost()
:_imageEffectPluginCache(*this)
{
    _properties.setStringProperty(kOfxPropName, POWITER_APPLICATION_NAME "Host");
    _properties.setStringProperty(kOfxPropLabel, POWITER_APPLICATION_NAME);
    _properties.setIntProperty(kOfxImageEffectHostPropIsBackground, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsOverlays, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultiResolution, 1);
    _properties.setIntProperty(kOfxImageEffectPropSupportsTiles, 1);
    _properties.setIntProperty(kOfxImageEffectPropTemporalClipAccess, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentRGBA, 0);
    _properties.setStringProperty(kOfxImageEffectPropSupportedComponents,  kOfxImageComponentAlpha, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, 0 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, 1);
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, 2 );
    _properties.setStringProperty(kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, 3 );

    _properties.setStringProperty(kOfxImageEffectPropSupportedPixelDepths,kOfxBitDepthFloat,0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipDepths, 0);
    _properties.setIntProperty(kOfxImageEffectPropSupportsMultipleClipPARs, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFrameRate, 0);
    _properties.setIntProperty(kOfxImageEffectPropSetableFielding, 0);
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomInteract, 1 );
    _properties.setIntProperty(kOfxParamHostPropSupportsStringAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsChoiceAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsBooleanAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropSupportsCustomAnimation, 0 );
    _properties.setIntProperty(kOfxParamHostPropMaxParameters, -1);
    _properties.setIntProperty(kOfxParamHostPropMaxPages, 0);
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 0 );
    _properties.setIntProperty(kOfxParamHostPropPageRowColumnCount, 0, 1 );

}

Powiter::OfxHost::~OfxHost()
{
    writeOFXCache();
}

OFX::Host::ImageEffect::Instance* Powiter::OfxHost::newInstance(void* ,
                                                     OFX::Host::ImageEffect::ImageEffectPlugin* plugin,
                                                     OFX::Host::ImageEffect::Descriptor& desc,
                                                     const std::string& context)
{
    assert(plugin);

    return new Powiter::OfxImageEffectInstance(plugin,desc,context,false);
}

/// Override this to create a descriptor, this makes the 'root' descriptor
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(OFX::Host::ImageEffect::ImageEffectPlugin* plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(plugin);
    return desc;
}

/// used to construct a context description, rootContext is the main context
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext,
                                                          OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(rootContext, plugin);
    return desc;
}

/// used to construct populate the cache
OFX::Host::ImageEffect::Descriptor *Powiter::OfxHost::makeDescriptor(const std::string &bundlePath,
                                                          OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
    assert(plugin);
    OFX::Host::ImageEffect::Descriptor *desc = new OFX::Host::ImageEffect::Descriptor(bundlePath, plugin);
    return desc;
}

/// message
OfxStatus Powiter::OfxHost::vmessage(const char* type,
                          const char* ,
                          const char* format,
                          va_list args)
{
    assert(type);
    assert(format);
    bool isQuestion = false;
    const char *prefix = "Message : ";
    if (strcmp(type, kOfxMessageLog) == 0) {
        prefix = "Log : ";
    }
    else if(strcmp(type, kOfxMessageFatal) == 0 ||
            strcmp(type, kOfxMessageError) == 0) {
        prefix = "Error : ";
    }
    else if(strcmp(type, kOfxMessageQuestion) == 0)  {
        prefix = "Question : ";
        isQuestion = true;
    }

    // Just dump our message to stdout, should be done with a proper
    // UI in a full ap, and post a dialogue for yes/no questions.
    fputs(prefix, stdout);
    vprintf(format, args);
    printf("\n");

    if(isQuestion) {
        /// cant do this properly inour example, as we need to raise a dialogue to ask a question, so just return yes
        return kOfxStatReplyYes;
    }
    else {
        return kOfxStatOK;
    }
}

OfxNode* Powiter::OfxHost::createOfxNode(const std::string& name,AppInstance* app) {
    OfxStatus stat;
    OFXPluginsIterator ofxPlugin = _ofxPlugins.find(name);
    if (ofxPlugin == _ofxPlugins.end()) {
        return NULL;
    }
    OFX::Host::ImageEffect::ImageEffectPlugin* plugin = _imageEffectPluginCache.getPluginById(ofxPlugin->second.first);
    if (!plugin) {
        return NULL;
    }
    const std::set<std::string>& contexts = plugin->getContexts();
    std::string context;

    if (contexts.size() == 1) {
        context = (*contexts.begin());
    }else{
        std::set<std::string>::iterator found = contexts.find(kOfxImageEffectContextGeneral);
        if(found != contexts.end()){
            context = *found;
        }else{
            found = contexts.find(kOfxImageEffectContextFilter);
            if(found != contexts.end()){
                context = *found;
            }else{
                found = contexts.find(kOfxImageEffectContextGenerator);
                if(found != contexts.end()){
                    context = *found;
                }else{
                    found = contexts.find(kOfxImageEffectContextTransition);
                    if(found != contexts.end()){
                        context = *found;
                    }else{
                        context = kOfxImageEffectContextPaint;
                    }
                }
            }
        }

    }

    bool rval = false;
    try{
        rval = plugin->getPluginHandle();
    } catch (const std::exception &e) {
        std::cout << "Error: Could not get plugin handle for plugin \"" << name << "\":" << e.what() << std::endl;
    }
    if(!rval) {
        return NULL;
    }
    OfxNode* node = new OfxNode(app,plugin,context);
    assert(node);
    Powiter::OfxImageEffectInstance* effect = node->effectInstance();
    if (effect) {
        stat = effect->createInstanceAction();
        assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault);
    } else {
        std::cout << "Error: Could not create effect instance for plugin \"" << name << "\"" << std::endl;
        delete node;
        return NULL;
    }

    /*must be called AFTER createInstanceAction!*/
    node->tryInitializeOverlayInteracts();
    return node;
}

QStringList Powiter::OfxHost::loadOFXPlugins() {
    QStringList pluginNames;

    assert(OFX::Host::PluginCache::getPluginCache());
    /// set the version label in the global cache
    OFX::Host::PluginCache::getPluginCache()->setCacheVersion(POWITER_APPLICATION_NAME "OFXCachev1");

    /// make an image effect plugin cache

    /// register the image effect cache with the global plugin cache
    _imageEffectPluginCache.registerInCache(*OFX::Host::PluginCache::getPluginCache());

#if defined(WINDOWS)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("C:\\Program Files\\Common Files\\OFX\\Nuke");
#endif
#if defined(__linux__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/usr/OFX/Nuke");
#endif
#if defined(__APPLE__)
    OFX::Host::PluginCache::getPluginCache()->addFileToPath("/Library/OFX/Nuke");
#endif

    /// now read an old cache
    // The cache location depends on the OS.
    // On OSX, it will be ~/Library/Caches/<organization>/<application>/OFXCache.xml
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation) + QDir::separator() + "OFXCache.xml";
#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QDir::separator() + "OFXCache.xml";
#endif
    std::ifstream ifs(ofxcachename.toStdString().c_str());
    if (ifs.is_open()) {
        OFX::Host::PluginCache::getPluginCache()->readCache(ifs);
        ifs.close();
    }
    OFX::Host::PluginCache::getPluginCache()->scanPluginFiles();

    /*Filling node name list and plugin grouping*/
    const std::vector<OFX::Host::ImageEffect::ImageEffectPlugin *>& plugins = _imageEffectPluginCache.getPlugins();
    for (unsigned int i = 0 ; i < plugins.size(); ++i) {
        OFX::Host::ImageEffect::ImageEffectPlugin* p = plugins[i];
        assert(p);
        if(p->getContexts().size() == 0)
            continue;
        QString name = p->getDescriptor().getLabel().c_str();
        if(name.isEmpty()){
            name = p->getDescriptor().getShortLabel().c_str();
        }

        if(name.isEmpty()){
            name = p->getDescriptor().getLongLabel().c_str();
        }

        QString rawName = name;
        QString id = p->getIdentifier().c_str();
        QString grouping = p->getDescriptor().getPluginGrouping().c_str();

        int pluginCount = p->getBinary()->getNPlugins();
        QString bundlePath;
        bundlePath = pluginCount > 1 ? p->getBinary()->getBundlePath().c_str() : "";
        QStringList groups = ofxExtractAllPartsOfGrouping(grouping,bundlePath);
        if (groups.size() >= 1) {
            name.append("  [");
            name.append(groups[0]);
            name.append("]");
        }
        assert(p->getBinary());
        QString iconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
        iconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
        iconFilename.append(id);
        iconFilename.append(".png");
        QString groupIconFilename;
        if (groups.size() >= 1) {
            groupIconFilename = QString(p->getBinary()->getBundlePath().c_str()) + "/Contents/Resources/";
            groupIconFilename.append(p->getDescriptor().getProps().getStringProperty(kOfxPropIcon,1).c_str());
            groupIconFilename.append(groups[0]);
//            if(bundlePath.size() > 0 && pluginCount > 1 && groups.size() > 1){
//                groupIconFilename.append('/');
//                groupIconFilename.append(groups[1]);
//            }
            groupIconFilename.append(".png");
        }
        emit toolButtonAdded(groups, rawName, iconFilename, groupIconFilename);
        _ofxPlugins.insert(make_pair(name.toStdString(), make_pair(id.toStdString(), grouping.toStdString())));
        pluginNames.append(name);
    }
    return pluginNames;
}

void Powiter::OfxHost::writeOFXCache(){
    /// and write a new cache, long version with everything in there
#if QT_VERSION < 0x050000
    QString ofxcachename = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);

#else
    QString ofxcachename = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
#endif
    QDir().mkpath(ofxcachename);
    ofxcachename +=  QDir::separator();
    ofxcachename += "OFXCache.xml";
    std::ofstream of(ofxcachename.toStdString().c_str());
    assert(of.is_open());
    assert(OFX::Host::PluginCache::getPluginCache());
    OFX::Host::PluginCache::getPluginCache()->writePluginCache(of);
    of.close();
    //Clean up, to be polite.
    OFX::Host::PluginCache::clearPluginCache();
}

<|endoftext|>


<commit_before>#include <chrono>
#include <iostream>

#include <mraa/common.hpp>

#include "SharpLCD.hpp"

static uint8_t reverseBits(uint8_t x) {
	x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
	x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
	x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
	return x;
}

static void mR(mraa::Result r) {
	if (r != mraa::SUCCESS) {
		mraa::printError(r);
		throw std::invalid_argument("MRAA error");
	}
}

static uint8_t pixelMask(int x) {
	return 0x80 >> (x % 8);
}

static uint8_t startMask(int x) {
	return 0xFF >> (x % 8);
}

static uint8_t endMask(int x) {
	return 0xFF80 >> (x % 8);
}

size_t SharpLCD::pixelIndex(uint16_t x, uint16_t y) {
	return bwidth * y + (x / 8);
}

void SharpLCD::applyMask(size_t index, uint8_t mask, uint8_t color) {
	// color is assumed to be 0x00(Black) or 0xFF (white)
	// this is ensured by translateColor
	uint8_t &p = frameBuf[index];
	p = (p | (mask & color)) & (~mask | color);
}

SharpLCD::SharpLCD(int width, int height) :	scs(15), vdd(31), pwm(20), spi(1) {
	c.size = sizeof(c);
	c.displayData = this;
	c.width = width;
	c.heigth = height;
	c.callPixelDraw = &SharpLCD::drawPixel;
	c.callPixelDrawMultiple = &SharpLCD::drawMultiplePixel;
	c.callLineDrawH = &SharpLCD::drawLineH;
	c.callLineDrawV = &SharpLCD::drawLineV;
	c.callRectFill = &SharpLCD::fillRect;
	c.callColorTranslate = &SharpLCD::translateColor;
	c.callFlush = &SharpLCD::flushBuffer;
	c.callClearDisplay = &SharpLCD::clearDisplay;

	bwidth = (width + 7) / 8;
	refreshEnabled = false;
	refreshRunning = false;
	refreshTerminate = false;
	frameCounter = 0;

	//GPIO Init
	mR(scs.useMmap(true));
	mR(scs.mode(mraa::MODE_PULLUP));
	mR(scs.dir(mraa::DIR_OUT));
	mR(vdd.mode(mraa::MODE_PULLUP));
	mR(vdd.dir(mraa::DIR_OUT));

	// Set SPI clock to 1MHz
	// LS013B4DN04: ƒSCLK: Typical 0.5MHz, Max 1.0MHz
	// LS013B7DH03: ƒSCLK: Typical 1.0MHz, Max 1.1MHz
	mR(spi.frequency(1000000));
	mR(spi.mode(mraa::SPI_MODE0));
	mR(spi.bitPerWord(8));
	mR(spi.lsbmode(false));

	// Set PWM to 60Hz
	// LS013B4DN04: fEXTCOMIN: Typical 1Hz, Max 60Hz
	// LS013B7DH03: fEXTCOMIN: Min 54Hz, Max 65Hz
	mR(pwm.period_us(16666));
	mR(pwm.pulsewidth_us(8333));

	cmdBuf[0].assign(2 + (2 + bwidth) * height, cmd_trail);
	// command
	cmdBuf[0][0] = cmd_writeLine;
	for (int row = 0; row < height; row++) {
		// line numbers
		cmdBuf[0][1 + row * (2 + bwidth)] = reverseBits(row + 1);
	}

	cmdBuf[1] = cmdBuf[0];
	cmdBufIndex = 0;

	frameBuf.assign(bwidth * height, 0xFF);
	flushBuffer(this);
}
SharpLCD::~SharpLCD() {
	refreshTerminate = true;
	dispThread.join();
	scs.write(false);
	vdd.write(false);
	pwm.enable(false);
}

void SharpLCD::enable() {
	if (refreshEnabled)
		return;
	// power up display
	mR(pwm.enable(true));
	mR(vdd.write(true));
	// start display thread
	refreshEnabled = true;
	refreshTerminate = false;

	dispThread = std::thread(&SharpLCD::refreshDisplay, this,
			cmdBuf[0].data(), cmdBuf[1].data(), cmdBuf[1].size());
}

void SharpLCD::disable() {
	refreshTerminate = true;
	dispThread.join();
	mR(vdd.write(false));
	mR(pwm.enable(false));
	refreshEnabled = false;
}

void SharpLCD::refreshDisplay(uint8_t *data0, uint8_t *data1, int len) {
	// for good measure, wait a few ms until things have settled
	std::this_thread::sleep_for(std::chrono::milliseconds(10));
	std::unique_lock<std::mutex> refreshLock(refreshMutex);
	refreshRunning = true;
	refreshCond.notify_all();

	uint8_t * const dataPtr[2] = {data0, data1};
	while (!refreshTerminate) {
		uint8_t index = cmdBufIndex;
		uint8_t *data = dataPtr[index];
		cmdBufUsed[index] = true;
		frameCounter++;
		refreshLock.unlock();
		std::chrono::steady_clock::time_point t = std::chrono::steady_clock::now();
		scs.write(true);
		std::this_thread::sleep_for(std::chrono::microseconds(6));
		//TODO check for error
		spi.transfer(data, NULL, len);
		std::this_thread::sleep_for(std::chrono::microseconds(2));
		scs.write(false);
		refreshCond.notify_all();
		std::this_thread::sleep_until(t + std::chrono::microseconds(16666));
		refreshLock.lock();
	}
	refreshRunning = false;
	refreshCond.notify_all();
}

void SharpLCD::drawPixel(void *tp, int16_t x, int16_t y, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	t.applyMask(t.pixelIndex(x, y), pixelMask(x), value);
}

void SharpLCD::drawMultiplePixel(void *tp, int16_t x, int16_t y, int16_t x0, int16_t count, int16_t bPP, const uint8_t *data, const uint32_t *pucPalette) {
	// this doesn't seem to be needed for anything
	std::cerr << "drawMultiplePixel is not supported" << std::endl;
}

void SharpLCD::drawLineH(void *tp, int16_t x1, int16_t x2, int16_t y, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	size_t sidx = t.pixelIndex(x1, y);
	size_t eidx = t.pixelIndex(x2, y);
	uint8_t smask = startMask(x1);
	uint8_t emask = endMask(x2);
	if (sidx == eidx) {
		t.applyMask(sidx, smask & emask, value);
	} else {
		t.applyMask(sidx, smask, value);
		for (size_t i=sidx+1; i<eidx; i++) {
			t.applyMask(i, 0xFF, value);
		}
		t.applyMask(eidx, emask, value);
	}
}

void SharpLCD::drawLineV(void *tp, int16_t x, int16_t y1, int16_t y2, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	uint8_t mask = pixelMask(x);
	for (int16_t y = y1; y<=y2; y++) {
		t.applyMask(t.pixelIndex(x, y), mask, value);
	}
}

void SharpLCD::fillRect(void *tp, const Graphics_Rectangle *rect, uint16_t value) {
	for (int16_t y=rect->yMin; y<=rect->yMax; y++) {
		SharpLCD::drawLineH(tp, rect->xMin, rect->xMax, y, value);
	}
}

uint32_t SharpLCD::translateColor(void *tp, uint32_t value) {
	return value ? 0xFF : 0x00;
}

uint32_t SharpLCD::getFrameCounter() {
	std::unique_lock<std::mutex> refreshLock(refreshMutex);
	return this->frameCounter;
}

void SharpLCD::flushBuffer(void *tp) {
	SharpLCD &t = *(SharpLCD*) tp;
	uint8_t freeIndex = 1 - t.cmdBufIndex;
	// skip command and line number
	uint8_t *dst = t.cmdBuf[freeIndex].data()+2;
	uint8_t *src = t.frameBuf.data();
	for (uint16_t i=0; i<t.c.heigth; i++) {
		for (size_t j=0; j<t.bwidth; j++) {
			*dst++ = *src++;
		}
		dst += 2; // skip trailer and line number
	}
	std::unique_lock<std::mutex> refreshLock(t.refreshMutex);
	t.cmdBufIndex = freeIndex;
	t.cmdBufUsed[freeIndex] = false;
	while (!t.cmdBufUsed[freeIndex] && t.refreshRunning) {
		t.refreshCond.wait(refreshLock);
	}
}

void SharpLCD::clearDisplay(void *tp, uint16_t value) {
	// value is assumed to be 0x00(Black) or 0xFF (white)
	// this is ensured by translateColor
	SharpLCD &t = *(SharpLCD*) tp;
	t.frameBuf.assign(t.frameBuf.size(), value);
}
<commit_msg>fix exception on join of enable() wasn't called<commit_after>#include <chrono>
#include <iostream>

#include <mraa/common.hpp>

#include "SharpLCD.hpp"

static uint8_t reverseBits(uint8_t x) {
	x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
	x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
	x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
	return x;
}

static void mR(mraa::Result r) {
	if (r != mraa::SUCCESS) {
		mraa::printError(r);
		throw std::invalid_argument("MRAA error");
	}
}

static uint8_t pixelMask(int x) {
	return 0x80 >> (x % 8);
}

static uint8_t startMask(int x) {
	return 0xFF >> (x % 8);
}

static uint8_t endMask(int x) {
	return 0xFF80 >> (x % 8);
}

size_t SharpLCD::pixelIndex(uint16_t x, uint16_t y) {
	return bwidth * y + (x / 8);
}

void SharpLCD::applyMask(size_t index, uint8_t mask, uint8_t color) {
	// color is assumed to be 0x00(Black) or 0xFF (white)
	// this is ensured by translateColor
	uint8_t &p = frameBuf[index];
	p = (p | (mask & color)) & (~mask | color);
}

SharpLCD::SharpLCD(int width, int height) :	scs(15), vdd(31), pwm(20), spi(1) {
	c.size = sizeof(c);
	c.displayData = this;
	c.width = width;
	c.heigth = height;
	c.callPixelDraw = &SharpLCD::drawPixel;
	c.callPixelDrawMultiple = &SharpLCD::drawMultiplePixel;
	c.callLineDrawH = &SharpLCD::drawLineH;
	c.callLineDrawV = &SharpLCD::drawLineV;
	c.callRectFill = &SharpLCD::fillRect;
	c.callColorTranslate = &SharpLCD::translateColor;
	c.callFlush = &SharpLCD::flushBuffer;
	c.callClearDisplay = &SharpLCD::clearDisplay;

	bwidth = (width + 7) / 8;
	refreshEnabled = false;
	refreshRunning = false;
	refreshTerminate = false;
	frameCounter = 0;

	//GPIO Init
	mR(scs.useMmap(true));
	mR(scs.mode(mraa::MODE_PULLUP));
	mR(scs.dir(mraa::DIR_OUT));
	mR(vdd.mode(mraa::MODE_PULLUP));
	mR(vdd.dir(mraa::DIR_OUT));

	// Set SPI clock to 1MHz
	// LS013B4DN04: ƒSCLK: Typical 0.5MHz, Max 1.0MHz
	// LS013B7DH03: ƒSCLK: Typical 1.0MHz, Max 1.1MHz
	mR(spi.frequency(1000000));
	mR(spi.mode(mraa::SPI_MODE0));
	mR(spi.bitPerWord(8));
	mR(spi.lsbmode(false));

	// Set PWM to 60Hz
	// LS013B4DN04: fEXTCOMIN: Typical 1Hz, Max 60Hz
	// LS013B7DH03: fEXTCOMIN: Min 54Hz, Max 65Hz
	mR(pwm.period_us(16666));
	mR(pwm.pulsewidth_us(8333));

	cmdBuf[0].assign(2 + (2 + bwidth) * height, cmd_trail);
	// command
	cmdBuf[0][0] = cmd_writeLine;
	for (int row = 0; row < height; row++) {
		// line numbers
		cmdBuf[0][1 + row * (2 + bwidth)] = reverseBits(row + 1);
	}

	cmdBuf[1] = cmdBuf[0];
	cmdBufIndex = 0;

	frameBuf.assign(bwidth * height, 0xFF);
	flushBuffer(this);
}
SharpLCD::~SharpLCD() {
	refreshTerminate = true;
	if (refreshEnabled) {
		dispThread.join();
	}
	scs.write(false);
	vdd.write(false);
	pwm.enable(false);
}

void SharpLCD::enable() {
	if (refreshEnabled)
		return;
	// power up display
	mR(pwm.enable(true));
	mR(vdd.write(true));
	// start display thread
	refreshEnabled = true;
	refreshTerminate = false;

	dispThread = std::thread(&SharpLCD::refreshDisplay, this,
			cmdBuf[0].data(), cmdBuf[1].data(), cmdBuf[1].size());
}

void SharpLCD::disable() {
	refreshTerminate = true;
	if (refreshEnabled) {
		dispThread.join();
		refreshEnabled = false;
	}
	mR(vdd.write(false));
	mR(pwm.enable(false));
}

void SharpLCD::refreshDisplay(uint8_t *data0, uint8_t *data1, int len) {
	// for good measure, wait a few ms until things have settled
	std::this_thread::sleep_for(std::chrono::milliseconds(10));
	std::unique_lock<std::mutex> refreshLock(refreshMutex);
	refreshRunning = true;
	refreshCond.notify_all();

	uint8_t * const dataPtr[2] = {data0, data1};
	while (!refreshTerminate) {
		uint8_t index = cmdBufIndex;
		uint8_t *data = dataPtr[index];
		cmdBufUsed[index] = true;
		frameCounter++;
		refreshLock.unlock();
		std::chrono::steady_clock::time_point t = std::chrono::steady_clock::now();
		scs.write(true);
		std::this_thread::sleep_for(std::chrono::microseconds(6));
		//TODO check for error
		spi.transfer(data, NULL, len);
		std::this_thread::sleep_for(std::chrono::microseconds(2));
		scs.write(false);
		refreshCond.notify_all();
		std::this_thread::sleep_until(t + std::chrono::microseconds(16666));
		refreshLock.lock();
	}
	refreshRunning = false;
	refreshCond.notify_all();
}

void SharpLCD::drawPixel(void *tp, int16_t x, int16_t y, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	t.applyMask(t.pixelIndex(x, y), pixelMask(x), value);
}

void SharpLCD::drawMultiplePixel(void *tp, int16_t x, int16_t y, int16_t x0, int16_t count, int16_t bPP, const uint8_t *data, const uint32_t *pucPalette) {
	// this doesn't seem to be needed for anything
	std::cerr << "drawMultiplePixel is not supported" << std::endl;
}

void SharpLCD::drawLineH(void *tp, int16_t x1, int16_t x2, int16_t y, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	size_t sidx = t.pixelIndex(x1, y);
	size_t eidx = t.pixelIndex(x2, y);
	uint8_t smask = startMask(x1);
	uint8_t emask = endMask(x2);
	if (sidx == eidx) {
		t.applyMask(sidx, smask & emask, value);
	} else {
		t.applyMask(sidx, smask, value);
		for (size_t i=sidx+1; i<eidx; i++) {
			t.applyMask(i, 0xFF, value);
		}
		t.applyMask(eidx, emask, value);
	}
}

void SharpLCD::drawLineV(void *tp, int16_t x, int16_t y1, int16_t y2, uint16_t value) {
	SharpLCD &t = *(SharpLCD*) tp;
	uint8_t mask = pixelMask(x);
	for (int16_t y = y1; y<=y2; y++) {
		t.applyMask(t.pixelIndex(x, y), mask, value);
	}
}

void SharpLCD::fillRect(void *tp, const Graphics_Rectangle *rect, uint16_t value) {
	for (int16_t y=rect->yMin; y<=rect->yMax; y++) {
		SharpLCD::drawLineH(tp, rect->xMin, rect->xMax, y, value);
	}
}

uint32_t SharpLCD::translateColor(void *tp, uint32_t value) {
	return value ? 0xFF : 0x00;
}

uint32_t SharpLCD::getFrameCounter() {
	std::unique_lock<std::mutex> refreshLock(refreshMutex);
	return this->frameCounter;
}

void SharpLCD::flushBuffer(void *tp) {
	SharpLCD &t = *(SharpLCD*) tp;
	uint8_t freeIndex = 1 - t.cmdBufIndex;
	// skip command and line number
	uint8_t *dst = t.cmdBuf[freeIndex].data()+2;
	uint8_t *src = t.frameBuf.data();
	for (uint16_t i=0; i<t.c.heigth; i++) {
		for (size_t j=0; j<t.bwidth; j++) {
			*dst++ = *src++;
		}
		dst += 2; // skip trailer and line number
	}
	std::unique_lock<std::mutex> refreshLock(t.refreshMutex);
	t.cmdBufIndex = freeIndex;
	t.cmdBufUsed[freeIndex] = false;
	while (!t.cmdBufUsed[freeIndex] && t.refreshRunning) {
		t.refreshCond.wait(refreshLock);
	}
}

void SharpLCD::clearDisplay(void *tp, uint16_t value) {
	// value is assumed to be 0x00(Black) or 0xFF (white)
	// this is ensured by translateColor
	SharpLCD &t = *(SharpLCD*) tp;
	t.frameBuf.assign(t.frameBuf.size(), value);
}
<|endoftext|>