<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.
 *
 *=========================================================================*/

#ifndef PoissonEditingWrappers_HPP
#define PoissonEditingWrappers_HPP

#include "PoissonEditingWrappers.h" // Appease syntax parser

// Submodules
#include "Helpers/Helpers.h"
#include "ITKHelpers/ITKHelpers.h"

// ITK
#include "itkAddImageFilter.h"
#include "itkImageRegionConstIterator.h"
#include "itkComposeImageFilter.h"
#include "itkLaplacianOperator.h"
#include "itkLaplacianImageFilter.h"
#include "itkVectorIndexSelectionCastImageFilter.h"

// Eigen
#include <Eigen/Sparse>

/** The terminology "targetImage" and "sourceImage" come from Poisson Cloning.
 * To interpret these arguments in a Poisson Filling context, there is no source image
 * (sourceImage must be nullptr), and the targetImage is the image to be filled.
 */
template <typename TImage>
void FillVectorImage(const TImage* const targetImage, const Mask* const mask,
                     const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
                     TImage* const output, const itk::ImageRegion<2>& regionToProcess,
                     const TImage* const sourceImage)
{
  std::cout << "FillVectorImage()" << std::endl;
  if(!mask)
  {
    throw std::runtime_error("You must specify a mask!");
  }

  if(guidanceFields.size() != targetImage->GetNumberOfComponentsPerPixel())
  {
    std::stringstream ss;
    ss << "There are " << targetImage->GetNumberOfComponentsPerPixel() << " channels but "
       << guidanceFields.size() << " guidance fields were specified (these must match).";
    throw std::runtime_error(ss.str());
  }

  itk::ImageRegion<2> holeBoundingBox =
      ITKHelpers::ComputeBoundingBox(mask, HoleMaskPixelTypeEnum::HOLE);

  // Adjust the hole bounding box to be in the target position
  itk::ImageRegion<2> holeBoundingBoxPositioned = holeBoundingBox;
  holeBoundingBoxPositioned.SetIndex(regionToProcess.GetIndex() +
                                     (holeBoundingBox.GetIndex() - mask->GetLargestPossibleRegion().GetIndex()));

  if(!targetImage->GetLargestPossibleRegion().IsInside(holeBoundingBoxPositioned))
  {
    std::cerr << "Cannot clone at this position! Source image holes are outside of the target image!" << std::endl;
    return;
  }

  // Crop the mask
  Mask::Pointer croppedMask = Mask::New();
  croppedMask->Allocate();
  ITKHelpers::ExtractRegion(mask, holeBoundingBox, croppedMask.GetPointer());
//  std::cout << "croppedMask region: " << croppedMask->GetLargestPossibleRegion() << std::endl;

  // Setup components of the channel-wise processing
  typedef itk::Image<typename TypeTraits<typename TImage::PixelType>::ComponentType, 2> ScalarImageType;

  typedef itk::ComposeImageFilter<ScalarImageType, TImage> ReassemblerType;
  typename ReassemblerType::Pointer reassembler = ReassemblerType::New();

  // Perform the Poisson reconstruction on each channel independently
  typedef typename TypeTraits<typename TImage::PixelType>::ComponentType ComponentType;
  typedef PoissonEditing<ComponentType> PoissonEditingFilterType;

  std::vector<typename ScalarImageType::Pointer> outputChannels(targetImage->GetNumberOfComponentsPerPixel());

  //std::cout << "There are " << targetImage->GetNumberOfComponentsPerPixel() << " components in the output image." << std::endl;
  for(unsigned int component = 0;
      component < targetImage->GetNumberOfComponentsPerPixel(); ++component)
  {
    std::cout << "Filling component " << component << std::endl;

    // Disassemble the target image into its components
    typedef itk::VectorIndexSelectionCastImageFilter<TImage, ScalarImageType>
        TargetDisassemblerType;
    typename TargetDisassemblerType::Pointer targetDisassembler =
        TargetDisassemblerType::New();
    targetDisassembler->SetIndex(component);
    targetDisassembler->SetInput(targetImage);
    targetDisassembler->Update();

    PoissonEditingParent::GuidanceFieldType::Pointer croppedGuidanceField =
        PoissonEditingParent::GuidanceFieldType::New();
    croppedGuidanceField->Allocate();
    ITKHelpers::ExtractRegion(guidanceFields[component].GetPointer(), holeBoundingBox,
                              croppedGuidanceField.GetPointer());
//    ITKHelpers::WriteImage(croppedGuidanceField.GetPointer(), "CroppedGuidanceField_" + std::to_string(component) + ".mha");

    // Perform the actual filling
    PoissonEditingFilterType poissonFilter;
    poissonFilter.SetTargetImage(targetDisassembler->GetOutput());
    poissonFilter.SetRegionToProcess(holeBoundingBoxPositioned);

    // Disassemble the source image into its components
    if(sourceImage)
    {
      std::cout << "Using sourceImage..." << std::endl;
      typedef itk::VectorIndexSelectionCastImageFilter<TImage, ScalarImageType>
          SourceDisassemblerType;
      typename SourceDisassemblerType::Pointer sourceDisassembler =
          SourceDisassemblerType::New();
      sourceDisassembler->SetIndex(component);
      sourceDisassembler->SetInput(sourceImage);
      sourceDisassembler->Update();

      typename ScalarImageType::Pointer croppedSourceImage =
          ScalarImageType::New();
      croppedSourceImage->Allocate();
      ITKHelpers::ExtractRegion(sourceDisassembler->GetOutput(), holeBoundingBox,
                                croppedSourceImage.GetPointer());

      poissonFilter.SetSourceImage(croppedSourceImage.GetPointer());
    }
    else
    {
        std::cout << "No source image provided - assuming Poisson Filling (versus Cloning)." << std::endl;
    }

    poissonFilter.SetGuidanceField(croppedGuidanceField.GetPointer());
    poissonFilter.SetMask(croppedMask.GetPointer());
    poissonFilter.FillMaskedRegion();

    outputChannels[component] = ScalarImageType::New();
    ITKHelpers::DeepCopy(poissonFilter.GetOutput(), outputChannels[component].GetPointer());

    reassembler->SetInput(component, outputChannels[component]);

  } // end loop over components

  reassembler->Update();
//   std::cout << "Output components per pixel: " << reassembler->GetOutput()->GetNumberOfComponentsPerPixel()
//             << std::endl;
//   std::cout << "Output size: " << reassembler->GetOutput()->GetLargestPossibleRegion().GetSize() << std::endl;

//  ITKHelpers::WriteImage(reassembler->GetOutput(), "Output.mha");

  ITKHelpers::DeepCopy(reassembler->GetOutput(), output);
}

/** Specialization for scalar images */
template <typename TScalarPixel>
void FillScalarImage(const itk::Image<TScalarPixel, 2>* const image,
                     const Mask* const mask,
                     const PoissonEditingParent::GuidanceFieldType* const guidanceField,
                     itk::Image<TScalarPixel, 2>* const output,
                     const itk::ImageRegion<2>& regionToProcess,
                     const itk::Image<TScalarPixel, 2>* const sourceImage)
{
  typedef PoissonEditing<TScalarPixel> PoissonEditingFilterType;
  PoissonEditingFilterType poissonFilter;

  poissonFilter.SetTargetImage(image);
  poissonFilter.SetRegionToProcess(regionToProcess);
  poissonFilter.SetGuidanceField(guidanceField);
  poissonFilter.SetMask(mask);

  // Perform the actual filling
  poissonFilter.FillMaskedRegion();

  ITKHelpers::DeepCopy(poissonFilter.GetOutput(), output);
}

/** For scalar images. */
template <typename TScalarPixel>
void FillImage(const itk::Image<TScalarPixel, 2>* const image, const Mask* const mask,
               const PoissonEditingParent::GuidanceFieldType* const guidanceField,
               itk::Image<TScalarPixel, 2>* const output,
               const itk::ImageRegion<2>& regionToProcess,
               const itk::Image<TScalarPixel, 2>* const sourceImage)
{
  FillScalarImage(image, mask, guidanceField, output, regionToProcess, sourceImage);
}

/** For multi-channel images with the same guidance field for each channel. */
template <typename TImage>
void
FillImage(const TImage* const image, const Mask* const mask,
          const PoissonEditingParent::GuidanceFieldType* guidanceField,
          TImage* const output, const itk::ImageRegion<2>& regionToProcess,
          const TImage* const sourceImage)
{
  std::cout << "FillImage with same guidance field for each channel." << std::endl;
  std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
      guidanceFields(image->GetNumberOfComponentsPerPixel(),
                     const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
  std::cout << "Duplicated guidance field for each of the "
            << image->GetNumberOfComponentsPerPixel() << " channels." << std::endl;
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For multi-channel images with different guidance fields for each channel. */
template <typename TImage>
void
FillImage(const TImage* const image, const Mask* const mask,
          const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
          TImage* const output, const itk::ImageRegion<2>& regionToProcess,
          const TImage* const sourceImage)
{
  // Always call the vector version, as it is the only one that makes sense
  // to have passed a collection of guidance fields.
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For Image<CovariantVector> images. */
template <typename TComponent, unsigned int NumberOfComponents>
void FillImage(const itk::Image<itk::CovariantVector<TComponent,
                                             NumberOfComponents>, 2>* const image,
               const Mask* const mask,
               const PoissonEditingParent::GuidanceFieldType* const guidanceField,
               itk::Image<itk::CovariantVector<TComponent,
                     NumberOfComponents>, 2>* const output,
               const itk::ImageRegion<2>& regionToProcess,
               const itk::Image<itk::CovariantVector<TComponent,
                     NumberOfComponents>, 2>* const sourceImage)
{
  std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
      guidanceFields(image->GetNumberOfComponentsPerPixel(),
                     const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For VectorImage images with the same guidance field for each channel.*/
template <typename TPixel>
static void
FillImage(const itk::VectorImage<TPixel>* const image,
          const Mask* const mask,
          const PoissonEditingParent::GuidanceFieldType* guidanceField,
          itk::VectorImage<TPixel>* const output,
          const itk::ImageRegion<2>& regionToProcess,
          const itk::VectorImage<TPixel>* const sourceImage)
{
    std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
        guidanceFields(image->GetNumberOfComponentsPerPixel(),
                       const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
    FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For VectorImages with different guidance fields for each channel. */
template <typename TPixel>
void
FillImage(const itk::VectorImage<TPixel>* const image,
          const Mask* const mask,
          const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
          itk::VectorImage<TPixel>* const output,
          const itk::ImageRegion<2>& regionToProcess,
          const itk::VectorImage<TPixel>* const sourceImage)
{
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

#endif
<commit_msg>Fix bug where source image wasn't used in scalar image filling.<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.
 *
 *=========================================================================*/

#ifndef PoissonEditingWrappers_HPP
#define PoissonEditingWrappers_HPP

#include "PoissonEditingWrappers.h" // Appease syntax parser

// Submodules
#include "Helpers/Helpers.h"
#include "ITKHelpers/ITKHelpers.h"

// ITK
#include "itkAddImageFilter.h"
#include "itkImageRegionConstIterator.h"
#include "itkComposeImageFilter.h"
#include "itkLaplacianOperator.h"
#include "itkLaplacianImageFilter.h"
#include "itkVectorIndexSelectionCastImageFilter.h"

// Eigen
#include <Eigen/Sparse>

/** The terminology "targetImage" and "sourceImage" come from Poisson Cloning.
 * To interpret these arguments in a Poisson Filling context, there is no source image
 * (sourceImage must be nullptr), and the targetImage is the image to be filled.
 */
template <typename TImage>
void FillVectorImage(const TImage* const targetImage, const Mask* const mask,
                     const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
                     TImage* const output, const itk::ImageRegion<2>& regionToProcess,
                     const TImage* const sourceImage)
{
  std::cout << "FillVectorImage()" << std::endl;
  if(!mask)
  {
    throw std::runtime_error("You must specify a mask!");
  }

  if(guidanceFields.size() != targetImage->GetNumberOfComponentsPerPixel())
  {
    std::stringstream ss;
    ss << "There are " << targetImage->GetNumberOfComponentsPerPixel() << " channels but "
       << guidanceFields.size() << " guidance fields were specified (these must match).";
    throw std::runtime_error(ss.str());
  }

  itk::ImageRegion<2> holeBoundingBox =
      ITKHelpers::ComputeBoundingBox(mask, HoleMaskPixelTypeEnum::HOLE);

  // Adjust the hole bounding box to be in the target position
  itk::ImageRegion<2> holeBoundingBoxPositioned = holeBoundingBox;
  holeBoundingBoxPositioned.SetIndex(regionToProcess.GetIndex() +
                                     (holeBoundingBox.GetIndex() - mask->GetLargestPossibleRegion().GetIndex()));

  if(!targetImage->GetLargestPossibleRegion().IsInside(holeBoundingBoxPositioned))
  {
    std::cerr << "Cannot clone at this position! Source image holes are outside of the target image!" << std::endl;
    return;
  }

  // Crop the mask
  Mask::Pointer croppedMask = Mask::New();
  croppedMask->Allocate();
  ITKHelpers::ExtractRegion(mask, holeBoundingBox, croppedMask.GetPointer());
//  std::cout << "croppedMask region: " << croppedMask->GetLargestPossibleRegion() << std::endl;

  // Setup components of the channel-wise processing
  typedef itk::Image<typename TypeTraits<typename TImage::PixelType>::ComponentType, 2> ScalarImageType;

  typedef itk::ComposeImageFilter<ScalarImageType, TImage> ReassemblerType;
  typename ReassemblerType::Pointer reassembler = ReassemblerType::New();

  // Perform the Poisson reconstruction on each channel independently
  typedef typename TypeTraits<typename TImage::PixelType>::ComponentType ComponentType;
  typedef PoissonEditing<ComponentType> PoissonEditingFilterType;

  std::vector<typename ScalarImageType::Pointer> outputChannels(targetImage->GetNumberOfComponentsPerPixel());

  //std::cout << "There are " << targetImage->GetNumberOfComponentsPerPixel() << " components in the output image." << std::endl;
  for(unsigned int component = 0;
      component < targetImage->GetNumberOfComponentsPerPixel(); ++component)
  {
    std::cout << "Filling component " << component << std::endl;

    // Disassemble the target image into its components
    typedef itk::VectorIndexSelectionCastImageFilter<TImage, ScalarImageType>
        TargetDisassemblerType;
    typename TargetDisassemblerType::Pointer targetDisassembler =
        TargetDisassemblerType::New();
    targetDisassembler->SetIndex(component);
    targetDisassembler->SetInput(targetImage);
    targetDisassembler->Update();

    PoissonEditingParent::GuidanceFieldType::Pointer croppedGuidanceField =
        PoissonEditingParent::GuidanceFieldType::New();
    croppedGuidanceField->Allocate();
    ITKHelpers::ExtractRegion(guidanceFields[component].GetPointer(), holeBoundingBox,
                              croppedGuidanceField.GetPointer());
//    ITKHelpers::WriteImage(croppedGuidanceField.GetPointer(), "CroppedGuidanceField_" + std::to_string(component) + ".mha");

    // Perform the actual filling
    PoissonEditingFilterType poissonFilter;
    poissonFilter.SetTargetImage(targetDisassembler->GetOutput());
    poissonFilter.SetRegionToProcess(holeBoundingBoxPositioned);

    // Disassemble the source image into its components
    if(sourceImage)
    {
      std::cout << "Using sourceImage..." << std::endl;
      typedef itk::VectorIndexSelectionCastImageFilter<TImage, ScalarImageType>
          SourceDisassemblerType;
      typename SourceDisassemblerType::Pointer sourceDisassembler =
          SourceDisassemblerType::New();
      sourceDisassembler->SetIndex(component);
      sourceDisassembler->SetInput(sourceImage);
      sourceDisassembler->Update();

      typename ScalarImageType::Pointer croppedSourceImage =
          ScalarImageType::New();
      croppedSourceImage->Allocate();
      ITKHelpers::ExtractRegion(sourceDisassembler->GetOutput(), holeBoundingBox,
                                croppedSourceImage.GetPointer());

      poissonFilter.SetSourceImage(croppedSourceImage.GetPointer());
    }
    else
    {
        std::cout << "No source image provided - assuming Poisson Filling (versus Cloning)." << std::endl;
    }

    poissonFilter.SetGuidanceField(croppedGuidanceField.GetPointer());
    poissonFilter.SetMask(croppedMask.GetPointer());
    poissonFilter.FillMaskedRegion();

    outputChannels[component] = ScalarImageType::New();
    ITKHelpers::DeepCopy(poissonFilter.GetOutput(), outputChannels[component].GetPointer());

    reassembler->SetInput(component, outputChannels[component]);

  } // end loop over components

  reassembler->Update();
//   std::cout << "Output components per pixel: " << reassembler->GetOutput()->GetNumberOfComponentsPerPixel()
//             << std::endl;
//   std::cout << "Output size: " << reassembler->GetOutput()->GetLargestPossibleRegion().GetSize() << std::endl;

//  ITKHelpers::WriteImage(reassembler->GetOutput(), "Output.mha");

  ITKHelpers::DeepCopy(reassembler->GetOutput(), output);
}

/** Specialization for scalar images */
template <typename TScalarPixel>
void FillScalarImage(const itk::Image<TScalarPixel, 2>* const image,
                     const Mask* const mask,
                     const PoissonEditingParent::GuidanceFieldType* const guidanceField,
                     itk::Image<TScalarPixel, 2>* const output,
                     const itk::ImageRegion<2>& regionToProcess,
                     const itk::Image<TScalarPixel, 2>* const sourceImage)
{
  typedef PoissonEditing<TScalarPixel> PoissonEditingFilterType;
  PoissonEditingFilterType poissonFilter;

  poissonFilter.SetTargetImage(image);
  poissonFilter.SetRegionToProcess(regionToProcess);
  poissonFilter.SetGuidanceField(guidanceField);
  poissonFilter.SetMask(mask);

  if(sourceImage)
  {
    poissonFilter.SetSourceImage(sourceImage);
  }

  // Perform the actual filling
  poissonFilter.FillMaskedRegion();

  ITKHelpers::DeepCopy(poissonFilter.GetOutput(), output);
}

/** For scalar images. */
template <typename TScalarPixel>
void FillImage(const itk::Image<TScalarPixel, 2>* const image, const Mask* const mask,
               const PoissonEditingParent::GuidanceFieldType* const guidanceField,
               itk::Image<TScalarPixel, 2>* const output,
               const itk::ImageRegion<2>& regionToProcess,
               const itk::Image<TScalarPixel, 2>* const sourceImage)
{
  FillScalarImage(image, mask, guidanceField, output, regionToProcess, sourceImage);
}

/** For multi-channel images with the same guidance field for each channel. */
template <typename TImage>
void
FillImage(const TImage* const image, const Mask* const mask,
          const PoissonEditingParent::GuidanceFieldType* guidanceField,
          TImage* const output, const itk::ImageRegion<2>& regionToProcess,
          const TImage* const sourceImage)
{
  std::cout << "FillImage with same guidance field for each channel." << std::endl;
  std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
      guidanceFields(image->GetNumberOfComponentsPerPixel(),
                     const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
  std::cout << "Duplicated guidance field for each of the "
            << image->GetNumberOfComponentsPerPixel() << " channels." << std::endl;
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For multi-channel images with different guidance fields for each channel. */
template <typename TImage>
void
FillImage(const TImage* const image, const Mask* const mask,
          const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
          TImage* const output, const itk::ImageRegion<2>& regionToProcess,
          const TImage* const sourceImage)
{
  // Always call the vector version, as it is the only one that makes sense
  // to have passed a collection of guidance fields.
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For Image<CovariantVector> images. */
template <typename TComponent, unsigned int NumberOfComponents>
void FillImage(const itk::Image<itk::CovariantVector<TComponent,
                                             NumberOfComponents>, 2>* const image,
               const Mask* const mask,
               const PoissonEditingParent::GuidanceFieldType* const guidanceField,
               itk::Image<itk::CovariantVector<TComponent,
                     NumberOfComponents>, 2>* const output,
               const itk::ImageRegion<2>& regionToProcess,
               const itk::Image<itk::CovariantVector<TComponent,
                     NumberOfComponents>, 2>* const sourceImage)
{
  std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
      guidanceFields(image->GetNumberOfComponentsPerPixel(),
                     const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For VectorImage images with the same guidance field for each channel.*/
template <typename TPixel>
static void
FillImage(const itk::VectorImage<TPixel>* const image,
          const Mask* const mask,
          const PoissonEditingParent::GuidanceFieldType* guidanceField,
          itk::VectorImage<TPixel>* const output,
          const itk::ImageRegion<2>& regionToProcess,
          const itk::VectorImage<TPixel>* const sourceImage)
{
    std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>
        guidanceFields(image->GetNumberOfComponentsPerPixel(),
                       const_cast<PoissonEditingParent::GuidanceFieldType*>(guidanceField));
    FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

/** For VectorImages with different guidance fields for each channel. */
template <typename TPixel>
void
FillImage(const itk::VectorImage<TPixel>* const image,
          const Mask* const mask,
          const std::vector<PoissonEditingParent::GuidanceFieldType::Pointer>& guidanceFields,
          itk::VectorImage<TPixel>* const output,
          const itk::ImageRegion<2>& regionToProcess,
          const itk::VectorImage<TPixel>* const sourceImage)
{
  FillVectorImage(image, mask, guidanceFields, output, regionToProcess, sourceImage);
}

#endif
<|endoftext|>


<commit_before>#include <string>
#include <cmath>
#include <memory>

#include <itkSpatialObjectReader.h>
#include <itkSpatialObjectWriter.h>
#include <vtkVersionMacros.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkPolyDataReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPolyDataWriter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkSmartPointer.h>
#include <vtkCell.h>
#include <vtkFloatArray.h>

#include "fiberio.h"

// hide function to this compilation unit
namespace
{
inline double SQ2(double x)
{
  return x * x;
}

};

void writeFiberFile(const std::string & filename, GroupType::Pointer fibergroup, bool saveProperties)
{
  // Make sure origins are updated
  fibergroup->ComputeObjectToWorldTransform();

  // ITK Spatial Object
  if( filename.rfind(".fib") != std::string::npos )
    {
    typedef itk::SpatialObjectWriter<3> WriterType;
    WriterType::Pointer writer  = WriterType::New();
    writer->SetInput(fibergroup);
    writer->SetFileName(filename);
    writer->Update();
    }
  // VTK Poly Data
  else if( filename.rfind(".vt") != std::string::npos )
    {
    // Build VTK data structure
    vtkSmartPointer<vtkPolyData>   polydata(vtkPolyData::New() );
    vtkSmartPointer<vtkFloatArray> tensorsdata(vtkFloatArray::New() );
    vtkSmartPointer<vtkIdList>     ids(vtkIdList::New() );
    vtkSmartPointer<vtkPoints>     pts(vtkPoints::New() );

    tensorsdata->SetNumberOfComponents(9);
    polydata->SetPoints(pts);

    ids->SetNumberOfIds(0);
    pts->SetNumberOfPoints(0);
    polydata->Allocate();
    vtkFloatArray *scalarFA = vtkFloatArray::New();
    vtkFloatArray *scalarMD = vtkFloatArray::New();
    vtkFloatArray *scalarRD = vtkFloatArray::New();
    vtkFloatArray *scalarAD = vtkFloatArray::New();
    scalarFA->SetNumberOfComponents(1);
    scalarFA->SetName("FA");
    scalarMD->SetNumberOfComponents(1);
    scalarMD->SetName("MD");
    scalarAD->SetNumberOfComponents(1);
    scalarAD->SetName("AD");
    scalarRD->SetNumberOfComponents(1);
    scalarRD->SetName("RD");

    std::auto_ptr<ChildrenListType> children(fibergroup->GetChildren(0) );
    typedef ChildrenListType::const_iterator IteratorType;
    for( IteratorType it = children->begin(); it != children->end(); it++ )
      {
      itk::SpatialObject<3>*        tmp = (*it).GetPointer();
      itk::DTITubeSpatialObject<3>* tube = dynamic_cast<itk::DTITubeSpatialObject<3> *>(tmp);
      unsigned int                  nPointsOnFiber = tube->GetNumberOfPoints();
      vtkIdType                     currentId = ids->GetNumberOfIds();
      for( unsigned int k = 0; k < nPointsOnFiber; k++ )
        {
        itk::Point<double, 3>  v(tube->GetPoint(k)->GetPosition() );
        itk::Vector<double, 3> spacing(tube->GetSpacing() );
        itk::Vector<double, 3> origin(tube->GetObjectToWorldTransform()->GetOffset() );

        // convert origin from LPS -> RAS
        origin[0] = -origin[0];
        origin[1] = -origin[1];

        vtkIdType id;
        // Need to multiply v by spacing and origin
        // Also negate the first to convert from LPS -> RAS
        // for slicer 3
        id = pts->InsertNextPoint(-v[0] * spacing[0] + origin[0],
                                  -v[1] * spacing[1] + origin[1],
                                  v[2] * spacing[2] + origin[2]);

        ids->InsertNextId(id);

        itk::DTITubeSpatialObjectPoint<3>* sopt = dynamic_cast<itk::DTITubeSpatialObjectPoint<3> *>(tube->GetPoint(k) );
        float                              vtktensor[9];
        vtktensor[0] = sopt->GetTensorMatrix()[0];
        vtktensor[1] = sopt->GetTensorMatrix()[1];
        vtktensor[2] = sopt->GetTensorMatrix()[2];
        vtktensor[3] = sopt->GetTensorMatrix()[1];
        vtktensor[4] = sopt->GetTensorMatrix()[3];
        vtktensor[5] = sopt->GetTensorMatrix()[4];
        vtktensor[6] = sopt->GetTensorMatrix()[2];
        vtktensor[7] = sopt->GetTensorMatrix()[4];
        vtktensor[8] = sopt->GetTensorMatrix()[5];

	//std::cout << "MD = " << sopt->GetField("md") << ", " ;

        scalarFA->InsertNextValue(sopt->GetField("fa"));
        scalarMD->InsertNextValue(sopt->GetField("md"));
        scalarAD->InsertNextValue(sopt->GetField("ad"));
        scalarRD->InsertNextValue(sopt->GetField("rd"));

        tensorsdata->InsertNextTupleValue(vtktensor);

        }
      polydata->InsertNextCell(VTK_POLY_LINE, nPointsOnFiber, ids->GetPointer(currentId) );
      }

    polydata->GetPointData()->SetTensors(tensorsdata);
    if (saveProperties)
      {
	polydata->GetPointData()->AddArray(scalarFA);
	polydata->GetPointData()->AddArray(scalarMD);
	polydata->GetPointData()->AddArray(scalarAD);
	polydata->GetPointData()->AddArray(scalarRD);
      }

    // Legacy
    if( filename.rfind(".vtk") != std::string::npos )
      {
      vtkSmartPointer<vtkPolyDataWriter> fiberwriter = vtkPolyDataWriter::New();
      fiberwriter->SetFileTypeToBinary();
      fiberwriter->SetFileName(filename.c_str() );
#if (VTK_MAJOR_VERSION < 6)
      fiberwriter->SetInput(polydata);
#else
      fiberwriter->SetInputData(polydata);
#endif
      fiberwriter->Update();
      }
    // XML
    else if( filename.rfind(".vtp") != std::string::npos )
      {
      vtkSmartPointer<vtkXMLPolyDataWriter> fiberwriter = vtkXMLPolyDataWriter::New();
      fiberwriter->SetFileName(filename.c_str() );
#if (VTK_MAJOR_VERSION < 6)
      fiberwriter->SetInput(polydata);
#else
      fiberwriter->SetInputData(polydata);
#endif
      fiberwriter->Update();
      }
    else
      {
      throw itk::ExceptionObject("Unknown file format for fibers");
      }
    }
  else
    {
    throw itk::ExceptionObject("Unknown file format for fibers");
    }
}

GroupType::Pointer readFiberFile(const std::string & filename)
{

  // ITK Spatial Object
  if( filename.rfind(".fib") != std::string::npos )
    {
    typedef itk::SpatialObjectReader<3, unsigned char> SpatialObjectReaderType;

    // Reading spatial object
    SpatialObjectReaderType::Pointer soreader = SpatialObjectReaderType::New();

    soreader->SetFileName(filename);
    soreader->Update();

    return soreader->GetGroup();
    }
  // VTK Poly Data
  else if( filename.rfind(".vt") != std::string::npos )
    {
    // Build up the principal data structure for fiber tracts
    GroupType::Pointer fibergroup = GroupType::New();

    vtkSmartPointer<vtkPolyData> fibdata(NULL);

    // Legacy
    if( filename.rfind(".vtk") != std::string::npos )
      {
      vtkSmartPointer<vtkPolyDataReader> reader(vtkPolyDataReader::New() );
      reader->SetFileName(filename.c_str() );
      reader->Update();
      fibdata = reader->GetOutput();

      }
    else if( filename.rfind(".vtp") != std::string::npos )
      {
      vtkSmartPointer<vtkXMLPolyDataReader> reader(vtkXMLPolyDataReader::New() );
      reader->SetFileName(filename.c_str() );
      reader->Update();
      fibdata = reader->GetOutput();
      }
    else
      {
      throw itk::ExceptionObject("Unknown file format for fibers");
      }

    typedef  itk::SymmetricSecondRankTensor<double, 3> ITKTensorType;
    typedef  ITKTensorType::EigenValuesArrayType       LambdaArrayType;

    // Iterate over VTK data
    const int nfib = fibdata->GetNumberOfCells();
    int       pindex = -1;
    for( int i = 0; i < nfib; ++i )
      {
      itk::DTITubeSpatialObject<3>::Pointer dtiTube = itk::DTITubeSpatialObject<3>::New();
      vtkSmartPointer<vtkCell>              fib = fibdata->GetCell(i);

      vtkSmartPointer<vtkPoints> points = fib->GetPoints();

      typedef itk::DTITubeSpatialObjectPoint<3> DTIPointType;
      std::vector<DTIPointType> pointsToAdd;

      vtkSmartPointer<vtkDataArray> fibtensordata = fibdata->GetPointData()->GetTensors();
      for( int j = 0; j < points->GetNumberOfPoints(); ++j )
        {
        ++pindex;

        double * coordinates = points->GetPoint(j);
        DTIPointType          pt;
        // Convert from RAS to LPS for vtk
        pt.SetPosition(-coordinates[0], -coordinates[1], coordinates[2]);
        pt.SetRadius(0.5);
        pt.SetColor(0.0, 1.0, 0.0);

        double * vtktensor = fibtensordata->GetTuple9(pindex);
        float                 floattensor[6];
        ITKTensorType         itktensor;

        floattensor[0] = itktensor[0] = vtktensor[0];
        floattensor[1] = itktensor[1] = vtktensor[1];
        floattensor[2] = itktensor[2] = vtktensor[2];
        floattensor[3] = itktensor[3] = vtktensor[4];
        floattensor[4] = itktensor[4] = vtktensor[5];
        floattensor[5] = itktensor[5] = vtktensor[8];

        pt.SetTensorMatrix(floattensor);

        LambdaArrayType lambdas;

        // Need to do do eigenanalysis of the tensor
        itktensor.ComputeEigenValues(lambdas);

        // FIXME: We should not be repeating this code here.  The code
        // for all these computations should be re-factored into a
        // common library.

        float md = (lambdas[0] + lambdas[1] + lambdas[2]) / 3;
        float fa = sqrt(1.5) * sqrt( (lambdas[0] - md) * (lambdas[0] - md)
                                     + (lambdas[1] - md) * (lambdas[1] - md)
                                     + (lambdas[2] - md) * (lambdas[2] - md) )
          / sqrt(lambdas[0] * lambdas[0] + lambdas[1] * lambdas[1] + lambdas[2] * lambdas[2]);

        float logavg = (log(lambdas[0]) + log(lambdas[1]) + log(lambdas[2]) ) / 3;

        float ga =  sqrt( SQ2(log(lambdas[0]) - logavg) \
                          + SQ2(log(lambdas[1]) - logavg) \
                          + SQ2(log(lambdas[2]) - logavg) );

	float rd = (lambdas[1] + lambdas[0])/2;

        pt.AddField("fa", fa);
        pt.AddField("ga", ga);
        pt.AddField("md", md);
        pt.AddField("l1", lambdas[2]);
        pt.AddField("l2", lambdas[1]);
        pt.AddField("l3", lambdas[0]);
        pt.AddField("rd", rd);

        pointsToAdd.push_back(pt);
        }

      dtiTube->SetPoints(pointsToAdd);
      fibergroup->AddSpatialObject(dtiTube);
      }
    return fibergroup;
    } // end process .vtk .vtp
  else
    {
    throw itk::ExceptionObject("Unknown fiber file");
    }
}
<commit_msg>COMP: backward compat to vtk5<commit_after>#include <string>
#include <cmath>
#include <memory>

#include <itkSpatialObjectReader.h>
#include <itkSpatialObjectWriter.h>
#include <vtkVersion.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkPolyDataReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPolyDataWriter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkSmartPointer.h>
#include <vtkCell.h>
#include <vtkFloatArray.h>

#include "fiberio.h"

// hide function to this compilation unit
namespace
{
inline double SQ2(double x)
{
  return x * x;
}

};

void writeFiberFile(const std::string & filename, GroupType::Pointer fibergroup, bool saveProperties)
{
  // Make sure origins are updated
  fibergroup->ComputeObjectToWorldTransform();

  // ITK Spatial Object
  if( filename.rfind(".fib") != std::string::npos )
    {
    typedef itk::SpatialObjectWriter<3> WriterType;
    WriterType::Pointer writer  = WriterType::New();
    writer->SetInput(fibergroup);
    writer->SetFileName(filename);
    writer->Update();
    }
  // VTK Poly Data
  else if( filename.rfind(".vt") != std::string::npos )
    {
    // Build VTK data structure
    vtkSmartPointer<vtkPolyData>   polydata(vtkPolyData::New() );
    vtkSmartPointer<vtkFloatArray> tensorsdata(vtkFloatArray::New() );
    vtkSmartPointer<vtkIdList>     ids(vtkIdList::New() );
    vtkSmartPointer<vtkPoints>     pts(vtkPoints::New() );

    tensorsdata->SetNumberOfComponents(9);
    polydata->SetPoints(pts);

    ids->SetNumberOfIds(0);
    pts->SetNumberOfPoints(0);
    polydata->Allocate();
    vtkFloatArray *scalarFA = vtkFloatArray::New();
    vtkFloatArray *scalarMD = vtkFloatArray::New();
    vtkFloatArray *scalarRD = vtkFloatArray::New();
    vtkFloatArray *scalarAD = vtkFloatArray::New();
    scalarFA->SetNumberOfComponents(1);
    scalarFA->SetName("FA");
    scalarMD->SetNumberOfComponents(1);
    scalarMD->SetName("MD");
    scalarAD->SetNumberOfComponents(1);
    scalarAD->SetName("AD");
    scalarRD->SetNumberOfComponents(1);
    scalarRD->SetName("RD");

    std::auto_ptr<ChildrenListType> children(fibergroup->GetChildren(0) );
    typedef ChildrenListType::const_iterator IteratorType;
    for( IteratorType it = children->begin(); it != children->end(); it++ )
      {
      itk::SpatialObject<3>*        tmp = (*it).GetPointer();
      itk::DTITubeSpatialObject<3>* tube = dynamic_cast<itk::DTITubeSpatialObject<3> *>(tmp);
      unsigned int                  nPointsOnFiber = tube->GetNumberOfPoints();
      vtkIdType                     currentId = ids->GetNumberOfIds();
      for( unsigned int k = 0; k < nPointsOnFiber; k++ )
        {
        itk::Point<double, 3>  v(tube->GetPoint(k)->GetPosition() );
        itk::Vector<double, 3> spacing(tube->GetSpacing() );
        itk::Vector<double, 3> origin(tube->GetObjectToWorldTransform()->GetOffset() );

        // convert origin from LPS -> RAS
        origin[0] = -origin[0];
        origin[1] = -origin[1];

        vtkIdType id;
        // Need to multiply v by spacing and origin
        // Also negate the first to convert from LPS -> RAS
        // for slicer 3
        id = pts->InsertNextPoint(-v[0] * spacing[0] + origin[0],
                                  -v[1] * spacing[1] + origin[1],
                                  v[2] * spacing[2] + origin[2]);

        ids->InsertNextId(id);

        itk::DTITubeSpatialObjectPoint<3>* sopt = dynamic_cast<itk::DTITubeSpatialObjectPoint<3> *>(tube->GetPoint(k) );
        float                              vtktensor[9];
        vtktensor[0] = sopt->GetTensorMatrix()[0];
        vtktensor[1] = sopt->GetTensorMatrix()[1];
        vtktensor[2] = sopt->GetTensorMatrix()[2];
        vtktensor[3] = sopt->GetTensorMatrix()[1];
        vtktensor[4] = sopt->GetTensorMatrix()[3];
        vtktensor[5] = sopt->GetTensorMatrix()[4];
        vtktensor[6] = sopt->GetTensorMatrix()[2];
        vtktensor[7] = sopt->GetTensorMatrix()[4];
        vtktensor[8] = sopt->GetTensorMatrix()[5];

	//std::cout << "MD = " << sopt->GetField("md") << ", " ;

        scalarFA->InsertNextValue(sopt->GetField("fa"));
        scalarMD->InsertNextValue(sopt->GetField("md"));
        scalarAD->InsertNextValue(sopt->GetField("ad"));
        scalarRD->InsertNextValue(sopt->GetField("rd"));

        tensorsdata->InsertNextTupleValue(vtktensor);

        }
      polydata->InsertNextCell(VTK_POLY_LINE, nPointsOnFiber, ids->GetPointer(currentId) );
      }

    polydata->GetPointData()->SetTensors(tensorsdata);
    if (saveProperties)
      {
	polydata->GetPointData()->AddArray(scalarFA);
	polydata->GetPointData()->AddArray(scalarMD);
	polydata->GetPointData()->AddArray(scalarAD);
	polydata->GetPointData()->AddArray(scalarRD);
      }

    // Legacy
    if( filename.rfind(".vtk") != std::string::npos )
      {
      vtkSmartPointer<vtkPolyDataWriter> fiberwriter = vtkPolyDataWriter::New();
      fiberwriter->SetFileTypeToBinary();
      fiberwriter->SetFileName(filename.c_str() );
#if (VTK_MAJOR_VERSION < 6)
      fiberwriter->SetInput(polydata);
#else
      fiberwriter->SetInputData(polydata);
#endif
      fiberwriter->Update();
      }
    // XML
    else if( filename.rfind(".vtp") != std::string::npos )
      {
      vtkSmartPointer<vtkXMLPolyDataWriter> fiberwriter = vtkXMLPolyDataWriter::New();
      fiberwriter->SetFileName(filename.c_str() );
#if (VTK_MAJOR_VERSION < 6)
      fiberwriter->SetInput(polydata);
#else
      fiberwriter->SetInputData(polydata);
#endif
      fiberwriter->Update();
      }
    else
      {
      throw itk::ExceptionObject("Unknown file format for fibers");
      }
    }
  else
    {
    throw itk::ExceptionObject("Unknown file format for fibers");
    }
}

GroupType::Pointer readFiberFile(const std::string & filename)
{

  // ITK Spatial Object
  if( filename.rfind(".fib") != std::string::npos )
    {
    typedef itk::SpatialObjectReader<3, unsigned char> SpatialObjectReaderType;

    // Reading spatial object
    SpatialObjectReaderType::Pointer soreader = SpatialObjectReaderType::New();

    soreader->SetFileName(filename);
    soreader->Update();

    return soreader->GetGroup();
    }
  // VTK Poly Data
  else if( filename.rfind(".vt") != std::string::npos )
    {
    // Build up the principal data structure for fiber tracts
    GroupType::Pointer fibergroup = GroupType::New();

    vtkSmartPointer<vtkPolyData> fibdata(NULL);

    // Legacy
    if( filename.rfind(".vtk") != std::string::npos )
      {
      vtkSmartPointer<vtkPolyDataReader> reader(vtkPolyDataReader::New() );
      reader->SetFileName(filename.c_str() );
      reader->Update();
      fibdata = reader->GetOutput();

      }
    else if( filename.rfind(".vtp") != std::string::npos )
      {
      vtkSmartPointer<vtkXMLPolyDataReader> reader(vtkXMLPolyDataReader::New() );
      reader->SetFileName(filename.c_str() );
      reader->Update();
      fibdata = reader->GetOutput();
      }
    else
      {
      throw itk::ExceptionObject("Unknown file format for fibers");
      }

    typedef  itk::SymmetricSecondRankTensor<double, 3> ITKTensorType;
    typedef  ITKTensorType::EigenValuesArrayType       LambdaArrayType;

    // Iterate over VTK data
    const int nfib = fibdata->GetNumberOfCells();
    int       pindex = -1;
    for( int i = 0; i < nfib; ++i )
      {
      itk::DTITubeSpatialObject<3>::Pointer dtiTube = itk::DTITubeSpatialObject<3>::New();
      vtkSmartPointer<vtkCell>              fib = fibdata->GetCell(i);

      vtkSmartPointer<vtkPoints> points = fib->GetPoints();

      typedef itk::DTITubeSpatialObjectPoint<3> DTIPointType;
      std::vector<DTIPointType> pointsToAdd;

      vtkSmartPointer<vtkDataArray> fibtensordata = fibdata->GetPointData()->GetTensors();
      for( int j = 0; j < points->GetNumberOfPoints(); ++j )
        {
        ++pindex;

        double * coordinates = points->GetPoint(j);
        DTIPointType          pt;
        // Convert from RAS to LPS for vtk
        pt.SetPosition(-coordinates[0], -coordinates[1], coordinates[2]);
        pt.SetRadius(0.5);
        pt.SetColor(0.0, 1.0, 0.0);

        double * vtktensor = fibtensordata->GetTuple9(pindex);
        float                 floattensor[6];
        ITKTensorType         itktensor;

        floattensor[0] = itktensor[0] = vtktensor[0];
        floattensor[1] = itktensor[1] = vtktensor[1];
        floattensor[2] = itktensor[2] = vtktensor[2];
        floattensor[3] = itktensor[3] = vtktensor[4];
        floattensor[4] = itktensor[4] = vtktensor[5];
        floattensor[5] = itktensor[5] = vtktensor[8];

        pt.SetTensorMatrix(floattensor);

        LambdaArrayType lambdas;

        // Need to do do eigenanalysis of the tensor
        itktensor.ComputeEigenValues(lambdas);

        // FIXME: We should not be repeating this code here.  The code
        // for all these computations should be re-factored into a
        // common library.

        float md = (lambdas[0] + lambdas[1] + lambdas[2]) / 3;
        float fa = sqrt(1.5) * sqrt( (lambdas[0] - md) * (lambdas[0] - md)
                                     + (lambdas[1] - md) * (lambdas[1] - md)
                                     + (lambdas[2] - md) * (lambdas[2] - md) )
          / sqrt(lambdas[0] * lambdas[0] + lambdas[1] * lambdas[1] + lambdas[2] * lambdas[2]);

        float logavg = (log(lambdas[0]) + log(lambdas[1]) + log(lambdas[2]) ) / 3;

        float ga =  sqrt( SQ2(log(lambdas[0]) - logavg) \
                          + SQ2(log(lambdas[1]) - logavg) \
                          + SQ2(log(lambdas[2]) - logavg) );

	float rd = (lambdas[1] + lambdas[0])/2;

        pt.AddField("fa", fa);
        pt.AddField("ga", ga);
        pt.AddField("md", md);
        pt.AddField("l1", lambdas[2]);
        pt.AddField("l2", lambdas[1]);
        pt.AddField("l3", lambdas[0]);
        pt.AddField("rd", rd);

        pointsToAdd.push_back(pt);
        }

      dtiTube->SetPoints(pointsToAdd);
      fibergroup->AddSpatialObject(dtiTube);
      }
    return fibergroup;
    } // end process .vtk .vtp
  else
    {
    throw itk::ExceptionObject("Unknown fiber file");
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "AttributeAnimation.h"
#include "Camera.h"
#include "CoreEvents.h"
#include "Engine.h"
#include "Font.h"
#include "Graphics.h"
#include "Input.h"
#include "Material.h"
#include "Model.h"
#include "Octree.h"
#include "Renderer.h"
#include "ResourceCache.h"
#include "Scene.h"
#include "StaticModel.h"
#include "Text.h"
#include "UI.h"

#include "StaticScene.h"

#include "DebugNew.h"

DEFINE_APPLICATION_MAIN(StaticScene)

StaticScene::StaticScene(Context* context) :
    Sample(context),
    yaw_(0.0f),
    pitch_(0.0f)
{
}

void StaticScene::Start()
{
    // Execute base class startup
    Sample::Start();

    // Create the scene content
    CreateScene();

    // Create the UI content
    CreateInstructions();

    // Setup the viewport for displaying the scene
    SetupViewport();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void StaticScene::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    scene_ = new Scene(context_);

    // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will
    // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it
    // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically
    // optimizing manner
    scene_->CreateComponent<Octree>();

    // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple
    // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger
    // (100 x 100 world units)
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

    // Create a directional light to the world so that we can see something. The light scene node's orientation controls the
    // light direction; we will use the SetDirection() function which calculates the orientation from a forward direction vector.
    // The light will use default settings (white light, no shadows)
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);

    AttributeAnimation* lightColorAnimation = new AttributeAnimation(context_);
    lightColorAnimation->AddKeyFrame(0.0f, Color(1.0f, 1.0f, 1.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(1.0f, Color(1.0f, 0.0f, 0.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(2.0f, Color(0.0f, 0.0f, 1.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(3.0f, Color(1.0f, 1.0f, 1.0f, 1.0f));
    light->SetAttributeAnimation("Color", lightColorAnimation);

    // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a
    // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains
    // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll
    // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the
    // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the
    // scene.
    const unsigned NUM_OBJECTS = 200;
    for (unsigned i = 0; i < NUM_OBJECTS; ++i)
    {
        Node* mushroomNode = scene_->CreateChild("Mushroom");
        mushroomNode->SetPosition(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));
        mushroomNode->SetRotation(Quaternion(0.0f, Random(360.0f), 0.0f));
        mushroomNode->SetScale(0.5f + Random(2.0f));
        StaticModel* mushroomObject = mushroomNode->CreateComponent<StaticModel>();
        mushroomObject->SetModel(cache->GetResource<Model>("Models/Mushroom.mdl"));
        mushroomObject->SetMaterial(cache->GetResource<Material>("Materials/Mushroom.xml"));
    }

    // Create a scene node for the camera, which we will move around
    // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically)
    cameraNode_ = scene_->CreateChild("Camera");
    cameraNode_->CreateComponent<Camera>();

    // Set an initial position for the camera scene node above the plane
    cameraNode_->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
}

void StaticScene::CreateInstructions()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    UI* ui = GetSubsystem<UI>();

    // Construct new Text object, set string to display and font to use
    Text* instructionText = ui->GetRoot()->CreateChild<Text>();
    instructionText->SetText("Use WASD keys and mouse to move");
    instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);

    // Position the text relative to the screen center
    instructionText->SetHorizontalAlignment(HA_CENTER);
    instructionText->SetVerticalAlignment(VA_CENTER);
    instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4);
}

void StaticScene::SetupViewport()
{
    Renderer* renderer = GetSubsystem<Renderer>();

    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera
    // at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to
    // use, but now we just use full screen and default render path configured in the engine command line options
    SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
    renderer->SetViewport(0, viewport);
}

void StaticScene::MoveCamera(float timeStep)
{
    // Do not move if the UI has a focused element (the console)
    if (GetSubsystem<UI>()->GetFocusElement())
        return;

    Input* input = GetSubsystem<Input>();

    // Movement speed as world units per second
    const float MOVE_SPEED = 20.0f;
    // Mouse sensitivity as degrees per pixel
    const float MOUSE_SENSITIVITY = 0.1f;

    // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
    IntVector2 mouseMove = input->GetMouseMove();
    yaw_ += MOUSE_SENSITIVITY * mouseMove.x_;
    pitch_ += MOUSE_SENSITIVITY * mouseMove.y_;
    pitch_ = Clamp(pitch_, -90.0f, 90.0f);

    // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
    cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));

    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
    // Use the TranslateRelative() function to move relative to the node's orientation. Alternatively we could
    // multiply the desired direction with the node's orientation quaternion, and use just Translate()
    if (input->GetKeyDown('W'))
        cameraNode_->TranslateRelative(Vector3::FORWARD * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('S'))
        cameraNode_->TranslateRelative(Vector3::BACK * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('A'))
        cameraNode_->TranslateRelative(Vector3::LEFT * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('D'))
        cameraNode_->TranslateRelative(Vector3::RIGHT * MOVE_SPEED * timeStep);
}

void StaticScene::SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent(E_UPDATE, HANDLER(StaticScene, HandleUpdate));
}

void StaticScene::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace Update;

    // Take the frame time step, which is stored as a float
    float timeStep = eventData[P_TIMESTEP].GetFloat();

    // Move the camera, scale movement with time step
    MoveCamera(timeStep);
}
<commit_msg>Add commend and use shared ptr for attribute animation. [ci skip]<commit_after>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "AttributeAnimation.h"
#include "Camera.h"
#include "CoreEvents.h"
#include "Engine.h"
#include "Font.h"
#include "Graphics.h"
#include "Input.h"
#include "Material.h"
#include "Model.h"
#include "Octree.h"
#include "Renderer.h"
#include "ResourceCache.h"
#include "Scene.h"
#include "StaticModel.h"
#include "Text.h"
#include "UI.h"

#include "StaticScene.h"

#include "DebugNew.h"

DEFINE_APPLICATION_MAIN(StaticScene)

StaticScene::StaticScene(Context* context) :
    Sample(context),
    yaw_(0.0f),
    pitch_(0.0f)
{
}

void StaticScene::Start()
{
    // Execute base class startup
    Sample::Start();

    // Create the scene content
    CreateScene();

    // Create the UI content
    CreateInstructions();

    // Setup the viewport for displaying the scene
    SetupViewport();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void StaticScene::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    scene_ = new Scene(context_);

    // Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will
    // show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it
    // is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically
    // optimizing manner
    scene_->CreateComponent<Octree>();

    // Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple
    // plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger
    // (100 x 100 world units)
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

    // Create a directional light to the world so that we can see something. The light scene node's orientation controls the
    // light direction; we will use the SetDirection() function which calculates the orientation from a forward direction vector.
    // The light will use default settings (white light, no shadows)
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);

    // Test code for attribute animation
    SharedPtr<AttributeAnimation> lightColorAnimation(new AttributeAnimation(context_));
    lightColorAnimation->AddKeyFrame(0.0f, Color(1.0f, 1.0f, 1.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(1.0f, Color(1.0f, 0.0f, 0.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(2.0f, Color(0.0f, 0.0f, 1.0f, 1.0f));
    lightColorAnimation->AddKeyFrame(3.0f, Color(1.0f, 1.0f, 1.0f, 1.0f));
    light->SetAttributeAnimation("Color", lightColorAnimation);

    // Create more StaticModel objects to the scene, randomly positioned, rotated and scaled. For rotation, we construct a
    // quaternion from Euler angles where the Y angle (rotation about the Y axis) is randomized. The mushroom model contains
    // LOD levels, so the StaticModel component will automatically select the LOD level according to the view distance (you'll
    // see the model get simpler as it moves further away). Finally, rendering a large number of the same object with the
    // same material allows instancing to be used, if the GPU supports it. This reduces the amount of CPU work in rendering the
    // scene.
    const unsigned NUM_OBJECTS = 200;
    for (unsigned i = 0; i < NUM_OBJECTS; ++i)
    {
        Node* mushroomNode = scene_->CreateChild("Mushroom");
        mushroomNode->SetPosition(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));
        mushroomNode->SetRotation(Quaternion(0.0f, Random(360.0f), 0.0f));
        mushroomNode->SetScale(0.5f + Random(2.0f));
        StaticModel* mushroomObject = mushroomNode->CreateComponent<StaticModel>();
        mushroomObject->SetModel(cache->GetResource<Model>("Models/Mushroom.mdl"));
        mushroomObject->SetMaterial(cache->GetResource<Material>("Materials/Mushroom.xml"));
    }

    // Create a scene node for the camera, which we will move around
    // The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically)
    cameraNode_ = scene_->CreateChild("Camera");
    cameraNode_->CreateComponent<Camera>();

    // Set an initial position for the camera scene node above the plane
    cameraNode_->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
}

void StaticScene::CreateInstructions()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    UI* ui = GetSubsystem<UI>();

    // Construct new Text object, set string to display and font to use
    Text* instructionText = ui->GetRoot()->CreateChild<Text>();
    instructionText->SetText("Use WASD keys and mouse to move");
    instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);

    // Position the text relative to the screen center
    instructionText->SetHorizontalAlignment(HA_CENTER);
    instructionText->SetVerticalAlignment(VA_CENTER);
    instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4);
}

void StaticScene::SetupViewport()
{
    Renderer* renderer = GetSubsystem<Renderer>();

    // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera
    // at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to
    // use, but now we just use full screen and default render path configured in the engine command line options
    SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
    renderer->SetViewport(0, viewport);
}

void StaticScene::MoveCamera(float timeStep)
{
    // Do not move if the UI has a focused element (the console)
    if (GetSubsystem<UI>()->GetFocusElement())
        return;

    Input* input = GetSubsystem<Input>();

    // Movement speed as world units per second
    const float MOVE_SPEED = 20.0f;
    // Mouse sensitivity as degrees per pixel
    const float MOUSE_SENSITIVITY = 0.1f;

    // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
    IntVector2 mouseMove = input->GetMouseMove();
    yaw_ += MOUSE_SENSITIVITY * mouseMove.x_;
    pitch_ += MOUSE_SENSITIVITY * mouseMove.y_;
    pitch_ = Clamp(pitch_, -90.0f, 90.0f);

    // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
    cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));

    // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
    // Use the TranslateRelative() function to move relative to the node's orientation. Alternatively we could
    // multiply the desired direction with the node's orientation quaternion, and use just Translate()
    if (input->GetKeyDown('W'))
        cameraNode_->TranslateRelative(Vector3::FORWARD * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('S'))
        cameraNode_->TranslateRelative(Vector3::BACK * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('A'))
        cameraNode_->TranslateRelative(Vector3::LEFT * MOVE_SPEED * timeStep);
    if (input->GetKeyDown('D'))
        cameraNode_->TranslateRelative(Vector3::RIGHT * MOVE_SPEED * timeStep);
}

void StaticScene::SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent(E_UPDATE, HANDLER(StaticScene, HandleUpdate));
}

void StaticScene::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace Update;

    // Take the frame time step, which is stored as a float
    float timeStep = eventData[P_TIMESTEP].GetFloat();

    // Move the camera, scale movement with time step
    MoveCamera(timeStep);
}
<|endoftext|>


<commit_before>// Copyright 2016 Vladimir Alyamkin. All Rights Reserved.

#include "VaRestPluginPrivatePCH.h"
#include "Base64.h"

//////////////////////////////////////////////////////////////////////////
// Helpers

FString UVaRestLibrary::PercentEncode(const FString& Source)
{
	FString OutText = Source;

	OutText = OutText.Replace(TEXT(" "), TEXT("%20"));
	OutText = OutText.Replace(TEXT("!"), TEXT("%21"));
	OutText = OutText.Replace(TEXT("\""), TEXT("%22"));
	OutText = OutText.Replace(TEXT("#"), TEXT("%23"));
	OutText = OutText.Replace(TEXT("$"), TEXT("%24"));
	OutText = OutText.Replace(TEXT("&"), TEXT("%26"));
	OutText = OutText.Replace(TEXT("'"), TEXT("%27"));
	OutText = OutText.Replace(TEXT("("), TEXT("%28"));
	OutText = OutText.Replace(TEXT(")"), TEXT("%29"));
	OutText = OutText.Replace(TEXT("*"), TEXT("%2A"));
	OutText = OutText.Replace(TEXT("+"), TEXT("%2B"));
	OutText = OutText.Replace(TEXT(","), TEXT("%2C"));
	OutText = OutText.Replace(TEXT("/"), TEXT("%2F"));
	OutText = OutText.Replace(TEXT(":"), TEXT("%3A"));
	OutText = OutText.Replace(TEXT(";"), TEXT("%3B"));
	OutText = OutText.Replace(TEXT("="), TEXT("%3D"));
	OutText = OutText.Replace(TEXT("?"), TEXT("%3F"));
	OutText = OutText.Replace(TEXT("@"), TEXT("%40"));
	OutText = OutText.Replace(TEXT("["), TEXT("%5B"));
	OutText = OutText.Replace(TEXT("]"), TEXT("%5D"));
	OutText = OutText.Replace(TEXT("{"), TEXT("%7B"));
	OutText = OutText.Replace(TEXT("}"), TEXT("%7D"));

	return OutText;
}

FString UVaRestLibrary::Base64Encode(const FString& Source)
{
	return FBase64::Encode(Source);
}

bool UVaRestLibrary::Base64Decode(const FString& Source, FString& Dest)
{
	return FBase64::Decode(Source, Dest);
}

bool UVaRestLibrary::Base64EncodeData(const TArray<uint8>& Data, FString& Dest){
	if (Data.Num()) {
		Dest=FBase64::Encode(Data);
		return true;
	}
	return false;
}

bool UVaRestLibrary::Base64DecodeData(const FString& Source, TArray<uint8>& Dest) {
	return FBase64::Decode(Source, Dest);
}

//////////////////////////////////////////////////////////////////////////
// Easy URL processing

TMap<UVaRestRequestJSON*, FVaRestCallResponse> UVaRestLibrary::RequestMap;

void UVaRestLibrary::CallURL(UObject* WorldContextObject, const FString& URL, ERequestVerb Verb, ERequestContentType ContentType, UVaRestJsonObject* VaRestJson, const FVaRestCallDelegate& Callback)
{
	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	if (World == nullptr)
	{
		UE_LOG(LogVaRest, Error, TEXT("UVaRestLibrary: Wrong world context"))
		return;
	}

	// Check we have valid data json
	if (VaRestJson == nullptr)
	{
		VaRestJson = UVaRestJsonObject::ConstructJsonObject(WorldContextObject);
	}

	UVaRestRequestJSON* Request = NewObject<UVaRestRequestJSON>();

	Request->SetVerb(Verb);
	Request->SetContentType(ContentType);
	Request->SetRequestObject(VaRestJson);

	FVaRestCallResponse Response;
	Response.Request = Request;
	Response.WorldContextObject = WorldContextObject;
	Response.Callback = Callback;

	Response.CompleteDelegateHandle = Request->OnStaticRequestComplete.AddStatic(&UVaRestLibrary::OnCallComplete);
	Response.FailDelegateHandle = Request->OnStaticRequestFail.AddStatic(&UVaRestLibrary::OnCallComplete);

	RequestMap.Add(Request, Response);

	Request->ResetResponseData();
	Request->ProcessURL(URL);
}

void UVaRestLibrary::OnCallComplete(UVaRestRequestJSON* Request)
{
	if (!RequestMap.Contains(Request))
	{
		return;
	}

	FVaRestCallResponse* Response = RequestMap.Find(Request);

	Request->OnStaticRequestComplete.Remove(Response->CompleteDelegateHandle);
	Request->OnStaticRequestFail.Remove(Response->FailDelegateHandle);

	Response->Callback.ExecuteIfBound(Request);

	Response->WorldContextObject = nullptr;
	Response->Request = nullptr;
	RequestMap.Remove(Request);
}
<commit_msg>Fix formatting issues<commit_after>// Copyright 2016 Vladimir Alyamkin. All Rights Reserved.

#include "VaRestPluginPrivatePCH.h"
#include "Base64.h"

//////////////////////////////////////////////////////////////////////////
// Helpers

FString UVaRestLibrary::PercentEncode(const FString& Source)
{
	FString OutText = Source;

	OutText = OutText.Replace(TEXT(" "), TEXT("%20"));
	OutText = OutText.Replace(TEXT("!"), TEXT("%21"));
	OutText = OutText.Replace(TEXT("\""), TEXT("%22"));
	OutText = OutText.Replace(TEXT("#"), TEXT("%23"));
	OutText = OutText.Replace(TEXT("$"), TEXT("%24"));
	OutText = OutText.Replace(TEXT("&"), TEXT("%26"));
	OutText = OutText.Replace(TEXT("'"), TEXT("%27"));
	OutText = OutText.Replace(TEXT("("), TEXT("%28"));
	OutText = OutText.Replace(TEXT(")"), TEXT("%29"));
	OutText = OutText.Replace(TEXT("*"), TEXT("%2A"));
	OutText = OutText.Replace(TEXT("+"), TEXT("%2B"));
	OutText = OutText.Replace(TEXT(","), TEXT("%2C"));
	OutText = OutText.Replace(TEXT("/"), TEXT("%2F"));
	OutText = OutText.Replace(TEXT(":"), TEXT("%3A"));
	OutText = OutText.Replace(TEXT(";"), TEXT("%3B"));
	OutText = OutText.Replace(TEXT("="), TEXT("%3D"));
	OutText = OutText.Replace(TEXT("?"), TEXT("%3F"));
	OutText = OutText.Replace(TEXT("@"), TEXT("%40"));
	OutText = OutText.Replace(TEXT("["), TEXT("%5B"));
	OutText = OutText.Replace(TEXT("]"), TEXT("%5D"));
	OutText = OutText.Replace(TEXT("{"), TEXT("%7B"));
	OutText = OutText.Replace(TEXT("}"), TEXT("%7D"));

	return OutText;
}

FString UVaRestLibrary::Base64Encode(const FString& Source)
{
	return FBase64::Encode(Source);
}

bool UVaRestLibrary::Base64Decode(const FString& Source, FString& Dest)
{
	return FBase64::Decode(Source, Dest);
}

bool UVaRestLibrary::Base64EncodeData(const TArray<uint8>& Data, FString& Dest)
{
	if (Data.Num() > 0)
	{
		Dest = FBase64::Encode(Data);
		return true;
	}

	return false;
}

bool UVaRestLibrary::Base64DecodeData(const FString& Source, TArray<uint8>& Dest)
{
	return FBase64::Decode(Source, Dest);
}

//////////////////////////////////////////////////////////////////////////
// Easy URL processing

TMap<UVaRestRequestJSON*, FVaRestCallResponse> UVaRestLibrary::RequestMap;

void UVaRestLibrary::CallURL(UObject* WorldContextObject, const FString& URL, ERequestVerb Verb, ERequestContentType ContentType, UVaRestJsonObject* VaRestJson, const FVaRestCallDelegate& Callback)
{
	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	if (World == nullptr)
	{
		UE_LOG(LogVaRest, Error, TEXT("UVaRestLibrary: Wrong world context"))
		return;
	}

	// Check we have valid data json
	if (VaRestJson == nullptr)
	{
		VaRestJson = UVaRestJsonObject::ConstructJsonObject(WorldContextObject);
	}

	UVaRestRequestJSON* Request = NewObject<UVaRestRequestJSON>();

	Request->SetVerb(Verb);
	Request->SetContentType(ContentType);
	Request->SetRequestObject(VaRestJson);

	FVaRestCallResponse Response;
	Response.Request = Request;
	Response.WorldContextObject = WorldContextObject;
	Response.Callback = Callback;

	Response.CompleteDelegateHandle = Request->OnStaticRequestComplete.AddStatic(&UVaRestLibrary::OnCallComplete);
	Response.FailDelegateHandle = Request->OnStaticRequestFail.AddStatic(&UVaRestLibrary::OnCallComplete);

	RequestMap.Add(Request, Response);

	Request->ResetResponseData();
	Request->ProcessURL(URL);
}

void UVaRestLibrary::OnCallComplete(UVaRestRequestJSON* Request)
{
	if (!RequestMap.Contains(Request))
	{
		return;
	}

	FVaRestCallResponse* Response = RequestMap.Find(Request);

	Request->OnStaticRequestComplete.Remove(Response->CompleteDelegateHandle);
	Request->OnStaticRequestFail.Remove(Response->FailDelegateHandle);

	Response->Callback.ExecuteIfBound(Request);

	Response->WorldContextObject = nullptr;
	Response->Request = nullptr;
	RequestMap.Remove(Request);
}
<|endoftext|>


<commit_before>//
// Created by tseyler on 2/9/16.
//

#include <iostream>
#include "sipproxy_pipeline.hpp"
#include <core/data/proto_net_pipe.hpp>

void
sipproxy_pipeline::ps_pipeline(const proto_net_in_data& req_data, proto_net_out_data& res_data)
{
    proto_net_pipe pipe(req_data);
    proto_net_data data_in = req_data;
    data_in.data_type(data_text);
    std::cout << "SipProxy Pipeline: Data in = " << data_in << std::endl;
   // res_data = pipe.ps_pipe_data_out();
    //proto_net_data data_out = res_data;
   // data_out.data_type(data_text);
   // std::cout << "SipProxy Pipeline: Data out = " << data_out << std::endl;
}

<commit_msg>Commented out pipe in siproxy_pipeline.<commit_after>//
// Created by tseyler on 2/9/16.
//

#include <iostream>
#include "sipproxy_pipeline.hpp"
#include <core/data/proto_net_pipe.hpp>

void
sipproxy_pipeline::ps_pipeline(const proto_net_in_data& req_data, proto_net_out_data& res_data)
{
   // proto_net_pipe pipe(req_data);
    proto_net_data data_in = req_data;
    data_in.data_type(data_text);
    std::cout << "SipProxy Pipeline: Data in = " << data_in << std::endl;
   // res_data = pipe.ps_pipe_data_out();
    //proto_net_data data_out = res_data;
   // data_out.data_type(data_text);
   // std::cout << "SipProxy Pipeline: Data out = " << data_out << std::endl;
}

<|endoftext|>


<commit_before>#include "Server.h"
#include "logging.h"

Server::Server(const char* localIP, int port){
  this->localIP = std::string(localIP);
  this->port = port;
  sizeAddressClient = sizeof(struct sockaddr);
  msg = new char[MAXMSG+1];
  /*
   * Configurações do endereço
  */
  memset(&address, 0, sizeof(address));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  //address.sin_addr.s_addr = INADDR_ANY;
  address.sin_addr.s_addr = inet_addr(localIP);
  connected = false;
  exitFlag = false;
  waitingFlag =false;
}

bool Server::start(){
  if(getSocket() == false){
    return false;
  }
  if(doBind() == false){
    return false;
  }
  if(startListening() == false){
    return false;
  }
  waitingFlag = false;
  return true;
}

bool Server::getSocket(){
  /*
   * Criando o Socket
   *
   * PARAM1: AF_INET ou AF_INET6 (IPV4 ou IPV6)
   * PARAM2: SOCK_STREAM ou SOCK_DGRAM
   * PARAM3: protocolo (IP, UDP, TCP, etc). Valor 0 escolhe automaticamente
  */
  socketId = socket(AF_INET, SOCK_STREAM, 0);
  //Verificar erros
  if (socketId == -1)
  {
      log("SERVER", "Failed to create socket()");
      return false;
  }
  return true;
}

bool Server::doBind(){
  //Conectando o socket a uma porta. Executado apenas no lado servidor
  if (bind (socketId, (struct sockaddr *)&address, sizeof(struct sockaddr)) == -1)
  {
    log("SERVER", std::string("Failed to bind() a port (") + std::to_string(port));
    return false;
  }else{
    return true;
  }
}

bool Server::startListening(){
  //Habilitando o servidor a receber conexoes do cliente
  if (listen( socketId, 10 ) == -1)
  {
      log("SERVER", std::string("Failed to listen() on ") + localIP + std::string("::") + std::to_string(port));
      return false;
  }else{
      return true;
  }
}

bool Server::isConnected(){
  return connected;
}

void Server::putMessage(std::string msgToSend){
    //std::string* bytes = new std::string(msgToSend.c_str());
    //sendQueue.push(bytes);
    m.lock();
    const char* bytesToSend = msgToSend.c_str();
    int bytesSent = send(connectionClientId, bytesToSend, strlen(bytesToSend), 0);
    if (bytesSent == 0)
    {
        log("SERVER", "Message sent: \nZero bytes, client finished connection");
        return;
    }
    else if(bytesSent<0)
    {
        error("SERVER", "ERROR: send returned an error" + std::to_string(errno));
        //cerr << "ERROR: send returned an error "<<errno<< endl; // this case is triggered
        return;
    }else if (bytesSent < strlen(bytesToSend)){
        log("SERVER", std::string("Message sent with less characters: \n") + std::string(bytesToSend, bytesSent));
    }else if (bytesSent > strlen(bytesToSend)){
        log("SERVER", std::string("Message sent with extra characters: \n")
            + std::string(bytesToSend) + std::string("+") + std::to_string(bytesSent-strlen(bytesToSend)));
    }else{
        log("SERVER", std::string("Message sent: \n") + std::string(bytesToSend));
    }
    m.unlock();
}

std::string Server::getMessage(){
  std::string *msg = messages.pop();
  if(msg == NULL){
    return "";
  }else{
    return *msg;
  }
}

void Server::startWaiting(){
  exitFlag = false;
  waitingFlag = true;
  std::thread theThread = std::thread(&Server::waitForClientAndReceive, this);
  theThread.detach();
}

void Server::stop(){
  //std::cout << "Server auto stopping itself\n";
  exitFlag = true;
}

bool Server::isWaiting(){
  return waitingFlag;
}

void Server::waitForClientAndReceive(){
  waitingFlag = true;
  //Servidor fica bloqueado esperando uma conexão do cliente
  log("SERVER", "Waiting for client...");
  connectionClientId = accept( socketId,(struct sockaddr *) &addressClient,&sizeAddressClient );

  log("SERVER", std::string("Client connected: ") + std::string(inet_ntoa(addressClient.sin_addr)));
  waitingFlag = false;
  connected = true;
  //Verificando erros
  if ( connectionClientId == -1)
  {
      log("SERVER", "Failed to accept() a client");
      return;
  }
  std::thread recvThread(&Server::receive, this);
  //std::thread sendThread(&Server::sendAll, this);
  recvThread.detach();
  //sendThread.detach();
}

void Server::receive(){
    while(!exitFlag){
      //receber uma msg do cliente
      //std::cout << "Server waiting for a message...\n";
      bytesread = recv(connectionClientId,msg,MAXMSG,0);
      if (bytesread == -1)
      {
          log("SERVER", "Message received: \nBroken message | Failed to recv()");
          break;
      }
      else if (bytesread == 0)
      {
          log("SERVER", "Message received: \nZero bytes, client finished connection");
          break;
      }
      //Inserir o caracter de fim de mensagem
      msg[bytesread] = '\0';
      log("SERVER", std::string("Message received: \n") + msg);
      std::string *s = new std::string(msg);
      messages.push(s);
      //close(connectionClientId);
    }
    waitingFlag = false;
    connected = false;
    close(connectionClientId);
    log("SERVER", "Connection to client finished, not receiving anymore");
}

/*void Server::sendAll(){
    while(!exitFlag){
        std::string* toSend = sendQueue.pop();
        if(toSend != NULL){
            const char* bytesToSend = toSend->c_str();
            int bytesSent = send(connectionClientId, bytesToSend, MAXMSG, 0);
            if (bytesSent == 0)
            {
                log("SERVER", "Message sent: \nZero bytes, client finished connection");
                break;
            }
            else if(bytesSent<0)
            {
                error("SERVER", "ERROR: send returned an error" + std::to_string(errno));
                //cerr << "ERROR: send returned an error "<<errno<< endl; // this case is triggered
                //return n;
            }else{
                log("SERVER", std::string("Message sent: \n") + std::string(bytesToSend, MAXMSG));
            }
            delete toSend;
            delete bytesToSend;
        }
    }
    log("SERVER", "Connection to client finished, not sending anymore");
}*/
<commit_msg>Receiving messages char by char, until '\0' is reached<commit_after>#include "Server.h"
#include "logging.h"

Server::Server(const char* localIP, int port){
  this->localIP = std::string(localIP);
  this->port = port;
  sizeAddressClient = sizeof(struct sockaddr);
  msg = new char[MAXMSG+1];
  /*
   * Configurações do endereço
  */
  memset(&address, 0, sizeof(address));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  //address.sin_addr.s_addr = INADDR_ANY;
  address.sin_addr.s_addr = inet_addr(localIP);
  connected = false;
  exitFlag = false;
  waitingFlag =false;
}

bool Server::start(){
  if(getSocket() == false){
    return false;
  }
  if(doBind() == false){
    return false;
  }
  if(startListening() == false){
    return false;
  }
  waitingFlag = false;
  return true;
}

bool Server::getSocket(){
  /*
   * Criando o Socket
   *
   * PARAM1: AF_INET ou AF_INET6 (IPV4 ou IPV6)
   * PARAM2: SOCK_STREAM ou SOCK_DGRAM
   * PARAM3: protocolo (IP, UDP, TCP, etc). Valor 0 escolhe automaticamente
  */
  socketId = socket(AF_INET, SOCK_STREAM, 0);
  //Verificar erros
  if (socketId == -1)
  {
      log("SERVER", "Failed to create socket()");
      return false;
  }
  return true;
}

bool Server::doBind(){
  //Conectando o socket a uma porta. Executado apenas no lado servidor
  if (bind (socketId, (struct sockaddr *)&address, sizeof(struct sockaddr)) == -1)
  {
    log("SERVER", std::string("Failed to bind() a port (") + std::to_string(port));
    return false;
  }else{
    return true;
  }
}

bool Server::startListening(){
  //Habilitando o servidor a receber conexoes do cliente
  if (listen( socketId, 10 ) == -1)
  {
      log("SERVER", std::string("Failed to listen() on ") + localIP + std::string("::") + std::to_string(port));
      return false;
  }else{
      return true;
  }
}

bool Server::isConnected(){
  return connected;
}

void Server::putMessage(std::string msgToSend){
    //std::string* bytes = new std::string(msgToSend.c_str());
    //sendQueue.push(bytes);
    m.lock();
    const char* bytesToSend = msgToSend.c_str();
    int bytesSent = send(connectionClientId, bytesToSend, strlen(bytesToSend), 0);
    if (bytesSent == 0)
    {
        log("SERVER", "Message sent: \nZero bytes, client finished connection");
        return;
    }
    else if(bytesSent<0)
    {
        error("SERVER", "ERROR: send returned an error" + std::to_string(errno));
        //cerr << "ERROR: send returned an error "<<errno<< endl; // this case is triggered
        return;
    }else if (bytesSent < strlen(bytesToSend)){
        log("SERVER", std::string("Message sent with less characters: \n") + std::string(bytesToSend, bytesSent));
    }else if (bytesSent > strlen(bytesToSend)){
        log("SERVER", std::string("Message sent with extra characters: \n")
            + std::string(bytesToSend) + std::string("+") + std::to_string(bytesSent-strlen(bytesToSend)));
    }else{
        log("SERVER", std::string("Message sent: \n") + std::string(bytesToSend));
    }
    m.unlock();
}

std::string Server::getMessage(){
  std::string *msg = messages.pop();
  if(msg == NULL){
    return "";
  }else{
    return *msg;
  }
}

void Server::startWaiting(){
  exitFlag = false;
  waitingFlag = true;
  std::thread theThread = std::thread(&Server::waitForClientAndReceive, this);
  theThread.detach();
}

void Server::stop(){
  //std::cout << "Server auto stopping itself\n";
  exitFlag = true;
}

bool Server::isWaiting(){
  return waitingFlag;
}

void Server::waitForClientAndReceive(){
  waitingFlag = true;
  //Servidor fica bloqueado esperando uma conexão do cliente
  log("SERVER", "Waiting for client...");
  connectionClientId = accept( socketId,(struct sockaddr *) &addressClient,&sizeAddressClient );

  log("SERVER", std::string("Client connected: ") + std::string(inet_ntoa(addressClient.sin_addr)));
  waitingFlag = false;
  connected = true;
  //Verificando erros
  if ( connectionClientId == -1)
  {
      log("SERVER", "Failed to accept() a client");
      return;
  }
  std::thread recvThread(&Server::receive, this);
  //std::thread sendThread(&Server::sendAll, this);
  recvThread.detach();
  //sendThread.detach();
}

void Server::receive(){
    while(!exitFlag){
      //receber uma msg do cliente
      //std::cout << "Server waiting for a message...\n";
      std::string msgBuilder = "";
      char* bytesread;
      bool messageBuilt = false;
      int nRead = 0;
      while(true){
          nRead = recv(connectionClientId,bytesread,1,0);
          if (nRead == -1)
          {
              log("SERVER", "Message received: \nBroken message | Failed to recv() (=-1)");
              break;
          }
          else if (nRead == 0)
          {
              log("SERVER", "Message received: \nZero bytes, client finished connection");
              break;
          }else{
              std::string charStr = std::string(bytesread, nRead);
              msgBuilder += charStr;
              if(charStr == "\0"){
                  messageBuilt = true;
                  break;
              }
          }
      }
      if(messageBuilt){
          log("SERVER", std::string("Message received: \n") + msg);
          std::string *s = new std::string(msg);
          messages.push(s);
      }else{
          exitFlag = true;
      }
    }

    waitingFlag = false;
    connected = false;
    close(connectionClientId);
    log("SERVER", "Connection to client finished, not receiving anymore");
}

/*void Server::sendAll(){
    while(!exitFlag){
        std::string* toSend = sendQueue.pop();
        if(toSend != NULL){
            const char* bytesToSend = toSend->c_str();
            int bytesSent = send(connectionClientId, bytesToSend, MAXMSG, 0);
            if (bytesSent == 0)
            {
                log("SERVER", "Message sent: \nZero bytes, client finished connection");
                break;
            }
            else if(bytesSent<0)
            {
                error("SERVER", "ERROR: send returned an error" + std::to_string(errno));
                //cerr << "ERROR: send returned an error "<<errno<< endl; // this case is triggered
                //return n;
            }else{
                log("SERVER", std::string("Message sent: \n") + std::string(bytesToSend, MAXMSG));
            }
            delete toSend;
            delete bytesToSend;
        }
    }
    log("SERVER", "Connection to client finished, not sending anymore");
}*/
<|endoftext|>


<commit_before>#include <KAI/Core/Detail/Function.h>

#include "MyTestStruct.h"

USING_NAMESPACE_KAI

using namespace std;

bool funCalled[5];

// just making some functions that we will also add to the runtime soon
void Function_0()
{
	funCalled[0] = true;
}

void Function_1(int )
{
	funCalled[1] = true;
}

String Function_2(int n, int f, String p)
{
	funCalled[2] = true;
	// KAI_TRACE_3(n, f, p);
	return p + "foo";
}

Object Function_3(Object object)
{
	funCalled[3] = true;
	KAI_TRACE_1(object);
	return object["num"];
}

TEST(TestFunctionScripting, Test)
{
	try
	{
		Console console;
		console.SetLanguage(Language::Rho);
		Object root = console.GetRoot();
		Registry &reg = console.GetRegistry();
		MyStruct::Register(reg);

		Pointer<MyStruct> mystruct = reg.New<MyStruct>();
		mystruct->num = 345;
		mystruct->string = "hello world";

		console.GetTree().AddSearchPath(root);//Pathname("/"));

		// Process::trace = 10;
		root["mystruct"] = mystruct;
		AddFunction(root, Function_0, Label("Function0"));
		AddFunction(root, Function_1, Label("Function1"));
		AddFunction(root, Function_2, Label("Function2"));
		AddFunction(root, Function_3, Label("Function3"));

		console.Execute("Function0()");
		console.Execute("Function1(42)");
		console.Execute("Function2(123, 3, \"bar\")");
		console.Execute("Function3(mystruct)");

		for (int n = 0; n < 2; ++n)
			ASSERT_TRUE(funCalled[n]);

		Value<Stack> stack = console.GetExecutor()->GetDataStack();
		EXPECT_EQ(stack->Size(), 2);
		EXPECT_EQ(ConstDeref<int>(stack->Pop()), 345);
		EXPECT_EQ(ConstDeref<String>(stack->Pop()), "barfoo");
		EXPECT_EQ(stack->Size(), 0);
	}

	catch (kai::Exception::Base &e)
	{
		cerr << e.ToString() << endl;
	}
	catch (std::exception &e)
	{
		cerr << e.what() << endl;
	}
}

<commit_msg>Remove unnecessary try/catch from test now that I found --gtest_use_exceptions.<commit_after>#include <KAI/Core/Detail/Function.h>

#include "MyTestStruct.h"

USING_NAMESPACE_KAI

using namespace std;

bool funCalled[5];

// just making some functions that we will also add to the runtime soon
void Function_0()
{
	funCalled[0] = true;
}

void Function_1(int )
{
	funCalled[1] = true;
}

String Function_2(int n, int f, String p)
{
	funCalled[2] = true;
	// KAI_TRACE_3(n, f, p);
	return p + "foo";
}

Object Function_3(Object object)
{
	funCalled[3] = true;
	KAI_TRACE_1(object);
	return object["num"];
}

TEST(TestFunctionScripting, Test)
{
	Console console;
	console.SetLanguage(Language::Rho);
	Object root = console.GetRoot();
	Registry &reg = console.GetRegistry();
	MyStruct::Register(reg);

	Pointer<MyStruct> mystruct = reg.New<MyStruct>();
	mystruct->num = 345;
	mystruct->string = "hello world";

	console.GetTree().AddSearchPath(root);//Pathname("/"));

	// Process::trace = 10;
	root["mystruct"] = mystruct;
	AddFunction(root, Function_0, Label("Function0"));
	AddFunction(root, Function_1, Label("Function1"));
	AddFunction(root, Function_2, Label("Function2"));
	AddFunction(root, Function_3, Label("Function3"));

	console.Execute("Function0()");
	console.Execute("Function1(42)");
	console.Execute("Function2(123, 3, \"bar\")");
	console.Execute("Function3(mystruct)");

	for (int n = 0; n < 2; ++n)
		ASSERT_TRUE(funCalled[n]);

	Value<Stack> stack = console.GetExecutor()->GetDataStack();
	EXPECT_EQ(stack->Size(), 2);
	EXPECT_EQ(ConstDeref<int>(stack->Pop()), 345);
	EXPECT_EQ(ConstDeref<String>(stack->Pop()), "barfoo");
	EXPECT_EQ(stack->Size(), 0);
}

<|endoftext|>


<commit_before>//
//  JdEnvironment.h
//  Jigidesign
//
//  Created by Steven Massey on 8/24/16.
//  Copyright © 2016 Jigidesign. All rights reserved.
//

#ifndef JdEnvironment_h
#define JdEnvironment_h

//#include "JdLibraryManager.h"
#include "JdServer.h"
#include "JdLibraryFactory.h"

#include "IJdBroadcaster.h"
#include "IJdTimers.h"

class JdEnvironment
{
	public:

	JdEnvironment				(bool i_enableTimers = false, bool i_deferSetup = false)
	:
	m_server					(m_libraries),
	m_timersEnabled				(i_enableTimers)
	{
		if (not i_deferSetup)
			Setup ();
	}

	virtual ~ JdEnvironment		()
	{
		Teardown ();
	}

	void DisableModules (cstr_t i_disabledModules)
	{
		if (i_disabledModules)
			m_disabledModules = Jd::SplitString (i_disabledModules, ",");
	}

	JdResult Setup (EpigramRef i_configuration = Epigram ())
	{
		JdResult result;

		if (not m_initialized)
		{
			result = m_server.Setup ();

			if (not result)
			{
				m_libraries.ParseLibraries (& JdLibraryFactory::Get ());

				if (i_configuration)
					m_server.SetConfiguration (i_configuration);

				for (auto moduleName : m_disabledModules)
				{
					//epilog_(normal,  "disable: %s", epistr (moduleName));

					m_libraries.DisableModule (moduleName);
				}

				if (m_timersEnabled)
				{
					result = jd_timers.Bind (& m_server);

					try
					{
//						jd_broadcaster.Bind (& m_server); // This is the notification delivery module
					}

					catch (...)
					{

					}

//					auto timers = JdPlatform::Get <IJdPlatform::Notification> ();
//					m_timer = timers->ScheduleTimer (10, this, 0);
				}

				if (not result)
				{
					auto scheduler = m_server.GetScheduler ();

					if (m_timersEnabled)
					{
						auto driver = jd_timers.Cast <IJdTimerDriver> ();

						scheduler->AddTimerThread (driver);
					}
	//				else
	//				scheduler->AddThreads (1);

					scheduler->Start ();
				}

				m_initialized = true;
			}
		}

		return result;
	}

	JdResult 		Teardown				();

	void  			RunMainThread			(f64 i_maxDurationInSeconds);
	void  			RunMainLoop				(f64 i_durationInSeconds);

	operator IJdModuleServer		()
	{
		return & m_server;
	}

	JdServer &						GetServer					() { return m_server; }

	protected ://------------------------------------------------------------------------------------------------------

	vector <string>					m_disabledModules;

	JdLibrarian						m_libraries;

	JdServer						m_server;

	IJdBroadcaster					jd_broadcaster;
	IJdTimers						jd_timers;

	bool							m_timersEnabled				= false;
	bool							m_initialized				= false;
};

struct JdLinkBasic		{ static void Setup (); };
struct JdLinkSimple		{ static void Setup (); };

#endif /* JdEnvironment_h */
<commit_msg>no message<commit_after>//
//  JdEnvironment.h
//  Jigidesign
//
//  Created by Steven Massey on 8/24/16.
//  Copyright © 2016 Jigidesign. All rights reserved.
//

#ifndef JdEnvironment_h
#define JdEnvironment_h

//#include "JdLibraryManager.h"
#include "JdServer.h"
#include "JdLibraryFactory.h"

#include "IJdBroadcaster.h"
#include "IJdTimers.h"

class JdEnvironment
{
	public:

	JdEnvironment				(bool i_enableTimers = false, bool i_deferSetup = false)
	:
	m_server					(m_libraries),
	m_timersEnabled				(i_enableTimers)
	{
		if (not i_deferSetup)
			Setup ();
	}

	virtual ~ JdEnvironment		()
	{
		Teardown ();
	}

	void DisableModules (cstr_t i_disabledModules)
	{
		if (i_disabledModules)
			m_disabledModules = Jd::SplitString (i_disabledModules, ",");
	}

	JdResult Setup (EpigramRef i_configuration = Epigram ())
	{
		JdResult result;

		if (not m_initialized)
		{
			result = m_server.Setup ();

			if (not result)
			{
				m_libraries.ParseLibraries (& JdLibraryFactory::Get ());

				if (i_configuration)
					m_server.SetConfiguration (i_configuration);

				for (auto moduleName : m_disabledModules)
				{
					//epilog_(normal,  "disable: %s", epistr (moduleName));

					m_libraries.DisableModule (moduleName);
				}

				if (m_timersEnabled)
				{
					result = jd_timers.Bind (& m_server);

					try
					{
//						jd_broadcaster.Bind (& m_server); // This is the notification delivery module
					}

					catch (...)
					{

					}

//					auto timers = JdPlatform::Get <IJdPlatform::Notification> ();
//					m_timer = timers->ScheduleTimer (10, this, 0);
				}

				if (not result)
				{
					auto scheduler = m_server.GetScheduler ();

					if (m_timersEnabled)
					{
						auto driver = jd_timers.Cast <IJdTimerDriver> ();

						scheduler->AddTimerThread (driver);
					}
					else scheduler->AddThreads (1);

					scheduler->Start ();
				}

				m_initialized = true;
			}
		}

		return result;
	}

	JdResult 		Teardown				();

	void  			RunMainThread			(f64 i_maxDurationInSeconds);
	void  			RunMainLoop				(f64 i_durationInSeconds);

	operator IJdModuleServer		()
	{
		return & m_server;
	}

	JdServer &						GetServer					() { return m_server; }

	protected ://------------------------------------------------------------------------------------------------------

	vector <string>					m_disabledModules;

	JdLibrarian						m_libraries;

	JdServer						m_server;

	IJdBroadcaster					jd_broadcaster;
	IJdTimers						jd_timers;

	bool							m_timersEnabled				= false;
	bool							m_initialized				= false;
};

struct JdLinkBasic		{ static void Setup (); };
struct JdLinkSimple		{ static void Setup (); };

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