<commit_before>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Linear;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  registration->SetTransformTypeToAffine();

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // two stages for each resolution:
  // first without interpolation, and then with interpolation
  int stage = 0;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (stage == 0)
    {
      registration->SetInterpolatorTypeToNearest();
      registration->SetTransformTolerance(minSpacing);
    }
    else
    {
      registration->SetInterpolatorType(interpolatorType);
      registration->SetTransformTolerance(transformTolerance);
    }
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " stage " << stage << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    if (stage == 1)
    {
      blurFactor /= 2.0;
      if (blurFactor < 0.9)
      {
        break;
      }
    }
    stage = (stage + 1) % 2;
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<commit_msg>Reduce registration to 3 stages (last stage is the same)<commit_after>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Affine;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  registration->SetTransformTypeToRigid();

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();

      registration->SetTransformTolerance(transformTolerance);
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }

      registration->SetTransformTolerance(transformTolerance*blurFactor);
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    blurFactor /= 2.0;
    if (blurFactor < 0.9)
    {
      break;
    }
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<|endoftext|>


<commit_before>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Affine;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  registration->SetTransformTypeToRigid();

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();

      registration->SetTransformTolerance(transformTolerance);
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }

      registration->SetTransformTolerance(transformTolerance*blurFactor);
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    blurFactor /= 2.0;
    if (blurFactor < 0.9)
    {
      break;
    }
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<commit_msg>Use Rigid registration (as was used before).<commit_after>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Rigid;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  registration->SetTransformTypeToRigid();

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();

      registration->SetTransformTolerance(transformTolerance);
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }

      registration->SetTransformTolerance(transformTolerance*blurFactor);
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    blurFactor /= 2.0;
    if (blurFactor < 0.9)
    {
      break;
    }
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<|endoftext|>


<commit_before>/**
 * @file lldynamictexture.cpp
 * @brief Implementation of LLViewerDynamicTexture class
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 *
 * Copyright (c) 2001-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lldynamictexture.h"

// Linden library includes
#include "llglheaders.h"
#include "llwindow.h"			// getPosition()

// Viewer includes
#include "llviewerwindow.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewertexture.h"
#include "llvertexbuffer.h"
#include "llviewerdisplay.h"
#include "llrender.h"

// static
LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ];
S32 LLViewerDynamicTexture::sNumRenders = 0;

//-----------------------------------------------------------------------------
// LLViewerDynamicTexture()
//-----------------------------------------------------------------------------
LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 components, EOrder order, BOOL clamp) :
	LLViewerTexture(width, height, components, FALSE),
	mClamp(clamp)
{
	llassert((1 <= components) && (components <= 4));

	generateGLTexture();

	llassert( 0 <= order && order < ORDER_COUNT );
	LLViewerDynamicTexture::sInstances[ order ].insert(this);
}

//-----------------------------------------------------------------------------
// LLViewerDynamicTexture()
//-----------------------------------------------------------------------------
LLViewerDynamicTexture::~LLViewerDynamicTexture()
{
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		LLViewerDynamicTexture::sInstances[order].erase(this);  // will fail in all but one case.
	}
}

//virtual
S8 LLViewerDynamicTexture::getType() const
{
	return LLViewerTexture::DYNAMIC_TEXTURE ;
}

//-----------------------------------------------------------------------------
// generateGLTexture()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::generateGLTexture()
{
	LLViewerTexture::generateGLTexture() ;
	generateGLTexture(-1, 0, 0, FALSE);
}

void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes)
{
	if (mComponents < 1 || mComponents > 4)
	{
		llerrs << "Bad number of components in dynamic texture: " << mComponents << llendl;
	}

	LLPointer<LLImageRaw> raw_image = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
	if (internal_format >= 0)
	{
		setExplicitFormat(internal_format, primary_format, type_format, swap_bytes);
	}
	createGLTexture(0, raw_image, 0, TRUE, LLViewerTexture::DYNAMIC_TEX);
	setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
	mGLTexturep->setGLTextureCreated(false);
}

//-----------------------------------------------------------------------------
// render()
//-----------------------------------------------------------------------------
BOOL LLViewerDynamicTexture::render()
{
	return FALSE;
}

//-----------------------------------------------------------------------------
// preRender()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::preRender(BOOL clear_depth)
{
	{
		// force rendering to on-screen portion of frame buffer
		LLCoordScreen window_pos;
		gViewerWindow->getWindow()->getPosition( &window_pos );
		mOrigin.set(0, gViewerWindow->getWindowHeightRaw() - mFullHeight);  // top left corner

		if (window_pos.mX < 0)
		{
			mOrigin.mX = -window_pos.mX;
		}
		if (window_pos.mY < 0)
		{
			mOrigin.mY += window_pos.mY;
			mOrigin.mY = llmax(mOrigin.mY, 0) ;
		}

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
	}
	// Set up camera
	LLViewerCamera* camera = LLViewerCamera::getInstance();
	mCamera.setOrigin(*camera);
	mCamera.setAxes(*camera);
	mCamera.setAspect(camera->getAspect());
	mCamera.setView(camera->getView());
	mCamera.setNear(camera->getNear());

	glViewport(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
	if (clear_depth)
	{
		glClear(GL_DEPTH_BUFFER_BIT);
	}
}

//-----------------------------------------------------------------------------
// postRender()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::postRender(BOOL success)
{
	{
		if (success)
		{
			if(mGLTexturep.isNull())
			{
				generateGLTexture() ;
			}
			if(!mGLTexturep->getHasGLTexture())
			{
				generateGLTexture() ;
			}

			if(gGLManager.mDebugGPU)
			{
				LLGLState::dumpStates() ;
			}
			success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
		}
	}

	// restore viewport
	gViewerWindow->setup2DViewport();

	// restore camera
	LLViewerCamera* camera = LLViewerCamera::getInstance();
	camera->setOrigin(mCamera);
	camera->setAxes(mCamera);
	camera->setAspect(mCamera.getAspect());
	camera->setView(mCamera.getView());
	camera->setNear(mCamera.getNear());
}

//-----------------------------------------------------------------------------
// static
// updateDynamicTextures()
// Calls update on each dynamic texture.  Calls each group in order: "first," then "middle," then "last."
//-----------------------------------------------------------------------------
BOOL LLViewerDynamicTexture::updateAllInstances()
{
	sNumRenders = 0;
	if (gGLManager.mIsDisabled)
	{
		return TRUE;
	}

	BOOL result = FALSE;
	BOOL ret = FALSE ;
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			if (dynamicTexture->needsRender())
			{
				if(gGLManager.mDebugGPU)
				{
					llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl;
					LLGLState::dumpStates() ;
				}

				glClear(GL_DEPTH_BUFFER_BIT);
				gDepthDirty = TRUE;

				gGL.color4f(1,1,1,1);
				dynamicTexture->preRender();	// Must be called outside of startRender()
				result = FALSE;
				if (dynamicTexture->render())
				{
					ret = TRUE ;
					result = TRUE;
					sNumRenders++;
				}
				gGL.flush();
				LLVertexBuffer::unbind();

				dynamicTexture->postRender(result);
			}
		}
	}

	return ret;
}

//-----------------------------------------------------------------------------
// static
// destroyGL()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::destroyGL()
{
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			dynamicTexture->destroyGLTexture() ;
		}
	}
}

//-----------------------------------------------------------------------------
// static
// restoreGL()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::restoreGL()
{
	if (gGLManager.mIsDisabled)
	{
		return ;
	}

	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			dynamicTexture->restoreGLTexture() ;
		}
	}
}
<commit_msg>fix for EXT-8730: crash at llrender/llimagegl.cpp(157) : error ERROR: checkTexSize: wrong texture size and discard level: width: 512 Height: 512 Current Level:<commit_after>/**
 * @file lldynamictexture.cpp
 * @brief Implementation of LLViewerDynamicTexture class
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 *
 * Copyright (c) 2001-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lldynamictexture.h"

// Linden library includes
#include "llglheaders.h"
#include "llwindow.h"			// getPosition()

// Viewer includes
#include "llviewerwindow.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewertexture.h"
#include "llvertexbuffer.h"
#include "llviewerdisplay.h"
#include "llrender.h"

// static
LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ];
S32 LLViewerDynamicTexture::sNumRenders = 0;

//-----------------------------------------------------------------------------
// LLViewerDynamicTexture()
//-----------------------------------------------------------------------------
LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 components, EOrder order, BOOL clamp) :
	LLViewerTexture(width, height, components, FALSE),
	mClamp(clamp)
{
	llassert((1 <= components) && (components <= 4));

	generateGLTexture();

	llassert( 0 <= order && order < ORDER_COUNT );
	LLViewerDynamicTexture::sInstances[ order ].insert(this);
}

//-----------------------------------------------------------------------------
// LLViewerDynamicTexture()
//-----------------------------------------------------------------------------
LLViewerDynamicTexture::~LLViewerDynamicTexture()
{
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		LLViewerDynamicTexture::sInstances[order].erase(this);  // will fail in all but one case.
	}
}

//virtual
S8 LLViewerDynamicTexture::getType() const
{
	return LLViewerTexture::DYNAMIC_TEXTURE ;
}

//-----------------------------------------------------------------------------
// generateGLTexture()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::generateGLTexture()
{
	LLViewerTexture::generateGLTexture() ;
	generateGLTexture(-1, 0, 0, FALSE);
}

void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes)
{
	if (mComponents < 1 || mComponents > 4)
	{
		llerrs << "Bad number of components in dynamic texture: " << mComponents << llendl;
	}

	LLPointer<LLImageRaw> raw_image = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
	if (internal_format >= 0)
	{
		setExplicitFormat(internal_format, primary_format, type_format, swap_bytes);
	}
	createGLTexture(0, raw_image, 0, TRUE, LLViewerTexture::DYNAMIC_TEX);
	setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
	mGLTexturep->setGLTextureCreated(false);
}

//-----------------------------------------------------------------------------
// render()
//-----------------------------------------------------------------------------
BOOL LLViewerDynamicTexture::render()
{
	return FALSE;
}

//-----------------------------------------------------------------------------
// preRender()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::preRender(BOOL clear_depth)
{
	{
		// force rendering to on-screen portion of frame buffer
		LLCoordScreen window_pos;
		gViewerWindow->getWindow()->getPosition( &window_pos );
		mOrigin.set(0, gViewerWindow->getWindowHeightRaw() - mFullHeight);  // top left corner

		if (window_pos.mX < 0)
		{
			mOrigin.mX = -window_pos.mX;
		}
		if (window_pos.mY < 0)
		{
			mOrigin.mY += window_pos.mY;
			mOrigin.mY = llmax(mOrigin.mY, 0) ;
		}

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
	}
	// Set up camera
	LLViewerCamera* camera = LLViewerCamera::getInstance();
	mCamera.setOrigin(*camera);
	mCamera.setAxes(*camera);
	mCamera.setAspect(camera->getAspect());
	mCamera.setView(camera->getView());
	mCamera.setNear(camera->getNear());

	glViewport(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
	if (clear_depth)
	{
		glClear(GL_DEPTH_BUFFER_BIT);
	}
}

//-----------------------------------------------------------------------------
// postRender()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::postRender(BOOL success)
{
	{
		if (success)
		{
			if(mGLTexturep.isNull())
			{
				generateGLTexture() ;
			}
			else if(!mGLTexturep->getHasGLTexture())
			{
				generateGLTexture() ;
			}
			else if(mGLTexturep->getDiscardLevel() != 0)//do not know how it happens, but regenerate one if it does.
			{
				generateGLTexture() ;
			}

			if(gGLManager.mDebugGPU)
			{
				LLGLState::dumpStates() ;
			}
			success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
		}
	}

	// restore viewport
	gViewerWindow->setup2DViewport();

	// restore camera
	LLViewerCamera* camera = LLViewerCamera::getInstance();
	camera->setOrigin(mCamera);
	camera->setAxes(mCamera);
	camera->setAspect(mCamera.getAspect());
	camera->setView(mCamera.getView());
	camera->setNear(mCamera.getNear());
}

//-----------------------------------------------------------------------------
// static
// updateDynamicTextures()
// Calls update on each dynamic texture.  Calls each group in order: "first," then "middle," then "last."
//-----------------------------------------------------------------------------
BOOL LLViewerDynamicTexture::updateAllInstances()
{
	sNumRenders = 0;
	if (gGLManager.mIsDisabled)
	{
		return TRUE;
	}

	BOOL result = FALSE;
	BOOL ret = FALSE ;
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			if (dynamicTexture->needsRender())
			{
				if(gGLManager.mDebugGPU)
				{
					llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl;
					LLGLState::dumpStates() ;
				}

				glClear(GL_DEPTH_BUFFER_BIT);
				gDepthDirty = TRUE;

				gGL.color4f(1,1,1,1);
				dynamicTexture->preRender();	// Must be called outside of startRender()
				result = FALSE;
				if (dynamicTexture->render())
				{
					ret = TRUE ;
					result = TRUE;
					sNumRenders++;
				}
				gGL.flush();
				LLVertexBuffer::unbind();

				dynamicTexture->postRender(result);
			}
		}
	}

	return ret;
}

//-----------------------------------------------------------------------------
// static
// destroyGL()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::destroyGL()
{
	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			dynamicTexture->destroyGLTexture() ;
		}
	}
}

//-----------------------------------------------------------------------------
// static
// restoreGL()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::restoreGL()
{
	if (gGLManager.mIsDisabled)
	{
		return ;
	}

	for( S32 order = 0; order < ORDER_COUNT; order++ )
	{
		for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin();
			 iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter)
		{
			LLViewerDynamicTexture *dynamicTexture = *iter;
			dynamicTexture->restoreGLTexture() ;
		}
	}
}
<|endoftext|>


<commit_before>#include "VirtualMachine.h"
#include "Machine.h"
#include <unistd.h>
#include <iostream>
#include <vector>
#include <queue>
#include "Thread.h"

#define NUM_RQS                                 4
#define VM_THREAD_PRIORITY_NIL                  ((TVMThreadPriority)0x00)

using namespace std;

extern "C" TVMMainEntry VMLoadModule(const char *module);
extern "C" void VMUnloadModule(void);
void fileCallback(void* calldata, int result);
void timerISR(void*);
void idle(void*);

TVMThreadID nextID; //increment every time a thread is created. Decrement never.
vector<Thread*> *threads;
Thread *tr, *mainThread;
queue<Thread*> *readyQ[NUM_RQS];

TVMStatus VMStart(int tickms, int machinetickms, int argc, char *argv[])
{
  nextID = 0;
  TVMThreadID idletid;

  TVMMainEntry mainFunc = VMLoadModule(argv[0]);
  if (!mainFunc)
  {
    return VM_STATUS_FAILURE;
  }//if mainFunc doesn't load, kill yourself

  threads = new vector<Thread*>;
  for (int i = 0; i < NUM_RQS; i++)
  {
    readyQ[i] = new queue<Thread*>;
  }//allocate memory for ready queues
  mainThread = new Thread;
  mainThread->setPriority(VM_THREAD_PRIORITY_NORMAL);
  mainThread->setState(VM_THREAD_STATE_READY);
  mainThread->setID(nextID);
  nextID++;
  readyQ[mainThread->getPriority()]->push(mainThread);
  tr = mainThread;
  VMThreadCreate(idle, NULL, 0x100000, VM_THREAD_PRIORITY_NIL, &idletid);
  MachineInitialize(machinetickms);
  MachineRequestAlarm((tickms*1000), timerISR, NULL);
  MachineEnableSignals();

  mainFunc(argc, argv);
  VMUnloadModule();
  MachineTerminate();
  delete threads;
  return VM_STATUS_SUCCESS;
} //VMStart

TVMStatus VMFileOpen(const char *filename, int flags, int mode, int *filedescriptor)
{
  tr->cd = -2; //impossible to have a negative file descriptor
  if (filename == NULL || filedescriptor == NULL)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }
  //change thread state to VM_THREAD_STATE_WAITING
  MachineFileOpen(filename, flags, mode, fileCallback, (void*)&(tr->cd));
  // void MachineFileOpen(const char *filename, int flags, int mode, TMachineFileCallback callback, void *calldata);
  while((tr->cd) < 0); //wait until file is actually open
  *filedescriptor = tr->cd;
  //change thread state to VM_THREAD_STATE_READY
  return VM_STATUS_SUCCESS;
//  return VM_STATUS_FAILURE;
} // VMFileOpen

TVMStatus VMFileClose(int filedescriptor)
{
  tr->cd = 1;
  // Make thread wait here.
  MachineFileClose(filedescriptor, fileCallback, (void*)&(tr->cd));
  while (tr->cd > 0); //wait until data has been altered
  // Change thread state to Stop waiting.
  if (tr->cd < 0)
  {
    return VM_STATUS_FAILURE;
  }//negative result is a failure
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileClose(int filedescriptor)

TVMStatus VMFileWrite(int filedescriptor, void *data, int *length)
{
  tr->cd = -739;
  if (!data || !length)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }
  MachineFileWrite(filedescriptor, data, *length, fileCallback, (void*)tr);
  tr->setState(VM_THREAD_STATE_WAITING);
  if(tr->cd >= 0)
  {
    return VM_STATUS_SUCCESS;
  }
  return VM_STATUS_FAILURE;
} // VMFileWrite

TVMStatus VMFileSeek(int filedescriptor, int offset, int whence, int *newoffset)
{
  // void MachineFileSeek(int fd, int offset, int whence, TMachineFileCallback callback, void *calldata);
  tr->cd = -728;
  // Make thread wait
  MachineFileSeek(filedescriptor, offset, whence, fileCallback, (void*)&(tr->cd));
  while (tr->cd == -728);
  if (newoffset)
  {
    *newoffset = tr->cd;
  }
  //make thread stop waiting
  if (tr->cd < 0)
    return VM_STATUS_FAILURE;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileseek(int filedescriptor, int offset, int whence, int *newoffset)

TVMStatus VMFileRead(int filedescriptor, void *data, int *length)
{
  tr->cd = -728;

  if (!data || !length)
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  // Make thread wait
  MachineFileRead(filedescriptor, data, *length, fileCallback, (void*)&(tr->cd));
  while (tr->cd == -728);
  *length = tr->cd;
  //make thread stop waiting

  if (tr->cd < 0)
    return VM_STATUS_FAILURE;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileseek(int filedescriptor, int offset, int whence, int *newoffset)

TVMStatus VMThreadSleep(TVMTick tick)
{
  if (tick == VM_TIMEOUT_IMMEDIATE)
  {
    tr->setState(VM_THREAD_STATE_READY);
    readyQ[tr->getPriority()]->push(tr);
  }// the current process yields the remainder of its processing quantum to the next ready process of equal priority.
  else if (tick == VM_TIMEOUT_INFINITE)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//invalid param
  else
  {
    tr->setTicks(tick);
    tr->setState(VM_THREAD_STATE_WAITING);
  } //does nothing while the number of ticks that have passed since entering this function is less than the number to sleep on
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadSleep(TVMTick tick)

TVMStatus VMThreadID(TVMThreadIDRef threadref)
{
  if (!threadref)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//if threadref is a null pointer
  threadref = tr->getIDRef();
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadID(TVMThreadIDRef threadref)

TVMStatus VMThreadState(TVMThreadID thread, TVMThreadStateRef state)
{
  bool found = false;
  if (!state)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//if stateref is a null pointer

  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    if (*((*itr)->getIDRef()) == thread)
    {
      *state = (*itr)->getState();
      found = true;
    }//found correct thread
  }//linear search through threads vector for the thread ID in question
  if (!found)
    return VM_STATUS_ERROR_INVALID_ID;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadState(TVMThreadID thread, TVMThreadStateRef state)

TVMStatus VMThreadActivate(TVMThreadID thread)
{
  bool found = false;
  Thread* nt = NULL;
  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    if (*((*itr)->getIDRef()) == thread)
    {
      nt = *itr;
      found = true;
    }//found correct thread
  }//linear search through threads vector for the thread ID in question
  if (!found)
    return VM_STATUS_ERROR_INVALID_ID;
  if (nt->getState() != VM_THREAD_STATE_DEAD)
    return VM_STATUS_ERROR_INVALID_STATE;
  nt->setState(VM_THREAD_STATE_READY);
  nt->getEntry();
  readyQ[nt->getPriority()]->push(nt);
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadActivate(TVMThreadID thread)

TVMStatus VMThreadCreate(TVMThreadEntry entry, void *param, TVMMemorySize memsize, TVMThreadPriority prio, TVMThreadIDRef tid)
{
  SMachineContext context;
  if (!entry || !tid)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//INVALID PARAMS, must not be NULL
  uint8_t *mem =  new uint8_t[memsize];
  Thread* t = new Thread(prio, VM_THREAD_STATE_DEAD, *tid = nextID, mem, memsize, entry, param);
  nextID++;
  threads->push_back(t);
  MachineContextCreate(&context, entry, param, (void*) mem, memsize);
  t->setContext(context);
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadCreate(TVMThreadEntry entry, void *param, TVMMemorySize memsize, TVMThreadPriority prio, TVMThreadIDRef tid)

void fileCallback(void* calldata, int result)
{
  Thread* cbt = (Thread*)calldata;
  cbt->setcd(result);
  while (cbt->getState() != VM_THREAD_STATE_WAITING);
  cbt->setState(VM_THREAD_STATE_READY);
  readyQ[cbt->getPriority()]->push(cbt);
}//void fileCallback(void* calldata, int result)

void timerISR(void*)
{
//  Thread *pt;

  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    (*itr)->decrementTicks();
  }//add one tick passed to every thread

//  pt = tr;
  if (!readyQ[VM_THREAD_PRIORITY_HIGH]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_HIGH]->front();
    readyQ[VM_THREAD_PRIORITY_HIGH]->pop();
  }//if there's anything in hi-pri, run it
  else if (!readyQ[VM_THREAD_PRIORITY_NORMAL]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_NORMAL]->front();
    readyQ[VM_THREAD_PRIORITY_NORMAL]->pop();
  }//if there's anything in med-pri, run it
  else if (!readyQ[VM_THREAD_PRIORITY_LOW]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_LOW]->front();
    readyQ[VM_THREAD_PRIORITY_LOW]->pop();
  }//if there's anything in low-pri, run it
  else
  {
    tr = readyQ[VM_THREAD_PRIORITY_NIL]->front();
    //need to pre-load this Q with the idle process (which just sleeps forever)
  }//if there's nothing in any of the RQs, spin
    MachineContextRestore(tr->getContextRef());
//    MachineContextSwitch(pt->getContextRef(), tr->getContextRef());
//  }//run thread for one tick
}//Timer ISR: Do Everything!

void idle(void*)
{
  while(1);
}//idles forever!

<commit_msg>I don't even remember what I changed here, but functionality is same as last commit.<commit_after>#include "VirtualMachine.h"
#include "Machine.h"
#include <unistd.h>
#include <iostream>
#include <vector>
#include <queue>
#include "Thread.h"

#define NUM_RQS                                 4
#define VM_THREAD_PRIORITY_NIL                  ((TVMThreadPriority)0x00)

using namespace std;

extern "C" TVMMainEntry VMLoadModule(const char *module);
extern "C" void VMUnloadModule(void);
void fileCallback(void* calldata, int result);
void timerISR(void*);
void idle(void*);
void scheduler();

TVMThreadID nextID; //increment every time a thread is created. Decrement never.
vector<Thread*> *threads;
Thread *tr, *mainThread, *pt, *sched;
queue<Thread*> *readyQ[NUM_RQS];

TVMStatus VMStart(int tickms, int machinetickms, int argc, char *argv[])
{
  nextID = 0;
  TVMThreadID idletid;

  TVMMainEntry mainFunc = VMLoadModule(argv[0]);
  if (!mainFunc)
  {
    return VM_STATUS_FAILURE;
  }//if mainFunc doesn't load, kill yourself

  threads = new vector<Thread*>;
  for (int i = 0; i < NUM_RQS; i++)
  {
    readyQ[i] = new queue<Thread*>;
  }//allocate memory for ready queues
  sched = new Thread;
  mainThread = new Thread;
  mainThread->setPriority(VM_THREAD_PRIORITY_NORMAL);
  mainThread->setState(VM_THREAD_STATE_READY);
  mainThread->setID(nextID);
  nextID++;
  readyQ[mainThread->getPriority()]->push(mainThread);
  tr = mainThread;
  VMThreadCreate(idle, NULL, 0x100000, VM_THREAD_PRIORITY_NIL, &idletid);
  MachineInitialize(machinetickms);
  MachineRequestAlarm((tickms*1000), timerISR, NULL);
  MachineEnableSignals();

  mainFunc(argc, argv);
  VMUnloadModule();
  MachineTerminate();
  delete threads;
  return VM_STATUS_SUCCESS;
} //VMStart

TVMStatus VMFileOpen(const char *filename, int flags, int mode, int *filedescriptor)
{
  tr->cd = -2; //impossible to have a negative file descriptor
  if (filename == NULL || filedescriptor == NULL)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }
  //change thread state to VM_THREAD_STATE_WAITING
  MachineFileOpen(filename, flags, mode, fileCallback, (void*)&(tr->cd));
  // void MachineFileOpen(const char *filename, int flags, int mode, TMachineFileCallback callback, void *calldata);
  while((tr->cd) < 0); //wait until file is actually open
  *filedescriptor = tr->cd;
  //change thread state to VM_THREAD_STATE_READY
  return VM_STATUS_SUCCESS;
//  return VM_STATUS_FAILURE;
} // VMFileOpen

TVMStatus VMFileClose(int filedescriptor)
{
  tr->cd = 1;
  // Make thread wait here.
  MachineFileClose(filedescriptor, fileCallback, (void*)&(tr->cd));
  while (tr->cd > 0); //wait until data has been altered
  // Change thread state to Stop waiting.
  if (tr->cd < 0)
  {
    return VM_STATUS_FAILURE;
  }//negative result is a failure
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileClose(int filedescriptor)

TVMStatus VMFileWrite(int filedescriptor, void *data, int *length)
{
  tr->cd = -739;
  if (!data || !length)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }
  MachineFileWrite(filedescriptor, data, *length, fileCallback, (void*)tr);
  tr->setState(VM_THREAD_STATE_WAITING);
  MachineContextSwitch(tr->getContextRef(), mainThread->getContextRef());
  if(tr->cd >= 0)
  {
    return VM_STATUS_SUCCESS;
  }
  return VM_STATUS_FAILURE;
} // VMFileWrite

TVMStatus VMFileSeek(int filedescriptor, int offset, int whence, int *newoffset)
{
  // void MachineFileSeek(int fd, int offset, int whence, TMachineFileCallback callback, void *calldata);
  tr->cd = -728;
  // Make thread wait
  MachineFileSeek(filedescriptor, offset, whence, fileCallback, (void*)&(tr->cd));
  while (tr->cd == -728);
  if (newoffset)
  {
    *newoffset = tr->cd;
  }
  //make thread stop waiting
  if (tr->cd < 0)
    return VM_STATUS_FAILURE;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileseek(int filedescriptor, int offset, int whence, int *newoffset)

TVMStatus VMFileRead(int filedescriptor, void *data, int *length)
{
  tr->cd = -728;

  if (!data || !length)
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  // Make thread wait
  MachineFileRead(filedescriptor, data, *length, fileCallback, (void*)&(tr->cd));
  while (tr->cd == -728);
  *length = tr->cd;
  //make thread stop waiting

  if (tr->cd < 0)
    return VM_STATUS_FAILURE;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMFileseek(int filedescriptor, int offset, int whence, int *newoffset)

TVMStatus VMThreadSleep(TVMTick tick)
{
  if (tick == VM_TIMEOUT_IMMEDIATE)
  {
    tr->setState(VM_THREAD_STATE_READY);
    readyQ[tr->getPriority()]->push(tr);
    MachineContextSwitch(tr->getContextRef(), mainThread->getContextRef());
  }// the current process yields the remainder of its processing quantum to the next ready process of equal priority.
  else if (tick == VM_TIMEOUT_INFINITE)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//invalid param
  else
  {
    tr->setTicks(tick);
    tr->setState(VM_THREAD_STATE_WAITING);
    MachineContextSwitch(tr->getContextRef(), mainThread->getContextRef());
  } //does nothing while the number of ticks that have passed since entering this function is less than the number to sleep on
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadSleep(TVMTick tick)

TVMStatus VMThreadID(TVMThreadIDRef threadref)
{
  if (!threadref)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//if threadref is a null pointer
  threadref = tr->getIDRef();
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadID(TVMThreadIDRef threadref)

TVMStatus VMThreadState(TVMThreadID thread, TVMThreadStateRef state)
{
  bool found = false;
  if (!state)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//if stateref is a null pointer

  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    if (*((*itr)->getIDRef()) == thread)
    {
      *state = (*itr)->getState();
      found = true;
    }//found correct thread
  }//linear search through threads vector for the thread ID in question
  if (!found)
    return VM_STATUS_ERROR_INVALID_ID;
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadState(TVMThreadID thread, TVMThreadStateRef state)

TVMStatus VMThreadActivate(TVMThreadID thread)
{
  bool found = false;
  Thread* nt = NULL;
  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    if (*((*itr)->getIDRef()) == thread)
    {
      nt = *itr;
      found = true;
    }//found correct thread
  }//linear search through threads vector for the thread ID in question
  if (!found)
    return VM_STATUS_ERROR_INVALID_ID;
  if (nt->getState() != VM_THREAD_STATE_DEAD)
    return VM_STATUS_ERROR_INVALID_STATE;
  nt->setState(VM_THREAD_STATE_READY);
  nt->getEntry();
  readyQ[nt->getPriority()]->push(nt);
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadActivate(TVMThreadID thread)

TVMStatus VMThreadCreate(TVMThreadEntry entry, void *param, TVMMemorySize memsize, TVMThreadPriority prio, TVMThreadIDRef tid)
{
  SMachineContext context;
  if (!entry || !tid)
  {
    return VM_STATUS_ERROR_INVALID_PARAMETER;
  }//INVALID PARAMS, must not be NULL
  uint8_t *mem =  new uint8_t[memsize];
  Thread* t = new Thread(prio, VM_THREAD_STATE_DEAD, *tid = nextID, mem, memsize, entry, param);
  nextID++;
  threads->push_back(t);
  MachineContextCreate(&context, entry, param, (void*) mem, memsize);
  t->setContext(context);
  return VM_STATUS_SUCCESS;
}//TVMStatus VMThreadCreate(TVMThreadEntry entry, void *param, TVMMemorySize memsize, TVMThreadPriority prio, TVMThreadIDRef tid)

void fileCallback(void* calldata, int result)
{
  Thread* cbt = (Thread*)calldata;
  cbt->setcd(result);
  while (cbt->getState() != VM_THREAD_STATE_WAITING);
  cbt->setState(VM_THREAD_STATE_READY);
  readyQ[cbt->getPriority()]->push(cbt);
}//void fileCallback(void* calldata, int result)

void timerISR(void*)
{
  for (vector<Thread*>::iterator itr = threads->begin(); itr != threads->end(); itr++)
  {
    (*itr)->decrementTicks();
  }//add one tick passed to every thread
  scheduler();
}//Timer ISR: Do Everything!

void scheduler()
{
  MachineContextSave(sched->getContextRef());
  if (!readyQ[VM_THREAD_PRIORITY_HIGH]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_HIGH]->front();
    readyQ[VM_THREAD_PRIORITY_HIGH]->pop();
  }//if there's anything in hi-pri, run it
  else if (!readyQ[VM_THREAD_PRIORITY_NORMAL]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_NORMAL]->front();
    readyQ[VM_THREAD_PRIORITY_NORMAL]->pop();
  }//if there's anything in med-pri, run it
  else if (!readyQ[VM_THREAD_PRIORITY_LOW]->empty())
  {
    tr = readyQ[VM_THREAD_PRIORITY_LOW]->front();
    readyQ[VM_THREAD_PRIORITY_LOW]->pop();
  }//if there's anything in low-pri, run it
  else
  {
    tr = readyQ[VM_THREAD_PRIORITY_NIL]->front();
    //need to pre-load this Q with the idle process (which just sleeps forever)
  }//if there's nothing in any of the RQs, spin
  MachineContextRestore(tr->getContextRef());
}//void scheduler()

void idle(void*)
{
  while(1);
}//idles forever!

<|endoftext|>