<commit_before>/**
 * @file Cosa/Pins.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 *
 * @section Description
 * Arduino pins abstractions; abstract, input, output, interrupt and
 * analog pin. Captures the mapping from Arduino to processor pins.
 * Forces declarative programming of pins in sketches.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Pins.h"
#include <util/delay_basic.h>

#define DELAY(us) _delay_loop_2((us) << 2)

uint8_t
Pin::await_change(uint8_t us)
{
  uint8_t res = 0;
  synchronized {
    if (is_set()) {
      while (is_set() && us--) res++;
    }
    else {
      while (is_clear() && us--) res++;
    }
  }
  return (res);
}

void
Pin::print(IOStream& stream)
{
  stream.printf_P(PSTR("Pin(pin = %d, sfr = %p, mask = %bd)"),
		  _pin, _sfr, _mask);
}

void
Pin::println(IOStream& stream)
{
  print();
  stream.println();
}

InterruptPin* InterruptPin::ext[2] = { 0, 0 };

ISR(INT0_vect)
{
  if (InterruptPin::ext[0] != 0)
    InterruptPin::ext[0]->on_interrupt();
}

ISR(INT1_vect)
{
  if (InterruptPin::ext[1] != 0)
    InterruptPin::ext[1]->on_interrupt();
}

void
OutputPin::pulse(uint16_t us)
{
  toggle();
  DELAY(us);
  toggle();
}

void
PWMPin::set(uint8_t duty)
{
  if (_pin == 5) {
    bit_set(TCCR0A, COM0B1);
    OCR0B = duty;
    return;
  }
  if (_pin == 6) {
    bit_set(TCCR0A, COM0A1);
    OCR0A = duty;
    return;
  }
  if (duty < 128)
    OutputPin::clear();
  else
    OutputPin::set();
}

void
PWMPin::set(uint16_t value, uint16_t min, uint16_t max)
{
  uint8_t duty;
  if (value <= min) duty = 0;
  else if (value >= max) duty = 255;
  else duty = (((uint32_t) (value - min)) << 8) / (max - min);
  set(duty);
}

uint8_t
PWMPin::get_duty()
{
  if (_pin == 5) return (OCR0B);
  if (_pin == 6) return (OCR0A);
  return (is_set());
}

AnalogPin* AnalogPin::sampling_pin = 0;

uint16_t
AnalogPin::sample()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  ADMUX = (_reference | ((_pin - 14) & 0xf));
  bit_mask_set(ADCSRA, _BV(ADEN) | _BV(ADSC));
  loop_until_bit_is_clear(ADCSRA, ADSC);
  return (_value = ADCW);
}

void
AnalogPin::sample_request()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  ADMUX = (_reference | (_pin - 14));
  bit_mask_set(ADCSRA, _BV(ADEN) | _BV(ADSC));
  if (_handler == 0) return;
  sampling_pin = this;
  bit_set(ADCSRA, ADIE);
}

uint16_t
AnalogPin::sample_await()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  return (_value = ADCW);
}

ISR(ADC_vect)
{
  bit_clear(ADCSRA, ADIE);
  AnalogPin* pin = AnalogPin::get_sampling_pin();
  if (pin != 0) pin->on_sample(ADCW);
}

void
AnalogPins::sample_next(AnalogPin* pin, void* env)
{
  AnalogPins* set = (AnalogPins*) env;
  if (set->_next != set->_count) {
    AnalogPin* pin = set->get_pin_at(set->_next++);
    pin->sample_request();
  }
  else if (set->_handler != 0) {
    set->_handler(set, set->_env);
  }
}

bool
AnalogPins::samples_request(InterruptHandler fn, void* env)
{
  if (AnalogPin::get_sampling_pin() != 0) return (0);
  if (fn != 0) {
    _handler = fn;
    _env = env;
  }
  get_pin_at(0)->sample_request();
  _next = 1;
  return (1);
}

<commit_msg>Adding OCA2A/B pin 11/3 to PWMPin handling.<commit_after>/**
 * @file Cosa/Pins.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 *
 * @section Description
 * Arduino pins abstractions; abstract, input, output, interrupt and
 * analog pin. Captures the mapping from Arduino to processor pins.
 * Forces declarative programming of pins in sketches.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Pins.h"
#include <util/delay_basic.h>

#define DELAY(us) _delay_loop_2((us) << 2)

uint8_t
Pin::await_change(uint8_t us)
{
  uint8_t res = 0;
  synchronized {
    if (is_set()) {
      while (is_set() && us--) res++;
    }
    else {
      while (is_clear() && us--) res++;
    }
  }
  return (res);
}

void
Pin::print(IOStream& stream)
{
  stream.printf_P(PSTR("Pin(pin = %d, sfr = %p, mask = %bd)"),
		  _pin, _sfr, _mask);
}

void
Pin::println(IOStream& stream)
{
  print();
  stream.println();
}

InterruptPin* InterruptPin::ext[2] = { 0, 0 };

ISR(INT0_vect)
{
  if (InterruptPin::ext[0] != 0)
    InterruptPin::ext[0]->on_interrupt();
}

ISR(INT1_vect)
{
  if (InterruptPin::ext[1] != 0)
    InterruptPin::ext[1]->on_interrupt();
}

void
OutputPin::pulse(uint16_t us)
{
  toggle();
  DELAY(us);
  toggle();
}

void
PWMPin::set(uint8_t duty)
{
  if (_pin == 3) {
    bit_set(TCCR2A, COM2A1);
    OCR2A = duty;
    return;
  }
  if (_pin == 5) {
    bit_set(TCCR0A, COM0B1);
    OCR0B = duty;
    return;
  }
  if (_pin == 6) {
    bit_set(TCCR0A, COM0A1);
    OCR0A = duty;
    return;
  }
  if (_pin == 11) {
    bit_set(TCCR2A, COM2B1);
    OCR2B = duty;
    return;
  }
  if (duty < 128)
    OutputPin::clear();
  else
    OutputPin::set();
}

void
PWMPin::set(uint16_t value, uint16_t min, uint16_t max)
{
  uint8_t duty;
  if (value <= min) duty = 0;
  else if (value >= max) duty = 255;
  else duty = (((uint32_t) (value - min)) << 8) / (max - min);
  set(duty);
}

uint8_t
PWMPin::get_duty()
{
  if (_pin == 5) return (OCR0B);
  if (_pin == 6) return (OCR0A);
  return (is_set());
}

AnalogPin* AnalogPin::sampling_pin = 0;

uint16_t
AnalogPin::sample()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  ADMUX = (_reference | ((_pin - 14) & 0xf));
  bit_mask_set(ADCSRA, _BV(ADEN) | _BV(ADSC));
  loop_until_bit_is_clear(ADCSRA, ADSC);
  return (_value = ADCW);
}

void
AnalogPin::sample_request()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  ADMUX = (_reference | (_pin - 14));
  bit_mask_set(ADCSRA, _BV(ADEN) | _BV(ADSC));
  if (_handler == 0) return;
  sampling_pin = this;
  bit_set(ADCSRA, ADIE);
}

uint16_t
AnalogPin::sample_await()
{
  loop_until_bit_is_clear(ADCSRA, ADSC);
  return (_value = ADCW);
}

ISR(ADC_vect)
{
  bit_clear(ADCSRA, ADIE);
  AnalogPin* pin = AnalogPin::get_sampling_pin();
  if (pin != 0) pin->on_sample(ADCW);
}

void
AnalogPins::sample_next(AnalogPin* pin, void* env)
{
  AnalogPins* set = (AnalogPins*) env;
  if (set->_next != set->_count) {
    AnalogPin* pin = set->get_pin_at(set->_next++);
    pin->sample_request();
  }
  else if (set->_handler != 0) {
    set->_handler(set, set->_env);
  }
}

bool
AnalogPins::samples_request(InterruptHandler fn, void* env)
{
  if (AnalogPin::get_sampling_pin() != 0) return (0);
  if (fn != 0) {
    _handler = fn;
    _env = env;
  }
  get_pin_at(0)->sample_request();
  _next = 1;
  return (1);
}

<|endoftext|>


<commit_before>#include "aquila/global.h"
#include "aquila/tools/TextPlot.h"
#include "UnitTest++/UnitTest++.h"
#include <cstddef>

SUITE(TextPlot)
{
    TEST(DefaultTitle)
    {
        Aquila::TextPlot plot;
        CHECK_EQUAL(plot.getTitle(), "Data plot");
    }

    TEST(CustomTitle)
    {
        Aquila::TextPlot plot;
        plot.setTitle("My plot");
        CHECK_EQUAL(plot.getTitle(), "My plot");
    }

    TEST(DefaultSize)
    {
        Aquila::TextPlot plot;
        CHECK_EQUAL(plot.getWidth(), 64u);
        CHECK_EQUAL(plot.getHeight(), 16u);
    }

    TEST(CustomSize)
    {
        Aquila::TextPlot plot;
        plot.setSize(80, 12);
        CHECK_EQUAL(plot.getWidth(), 80u);
        CHECK_EQUAL(plot.getHeight(), 12u);
    }
}
<commit_msg>Basic sanity check for plotting sine wave.<commit_after>#include "aquila/global.h"
#include "aquila/source/generator/SineGenerator.h"
#include "aquila/tools/TextPlot.h"
#include "UnitTest++/UnitTest++.h"
#include <cstddef>
#include <sstream>

SUITE(TextPlot)
{
    TEST(DefaultTitle)
    {
        Aquila::TextPlot plot;
        CHECK_EQUAL(plot.getTitle(), "Data plot");
    }

    TEST(CustomTitle)
    {
        Aquila::TextPlot plot;
        plot.setTitle("My plot");
        CHECK_EQUAL(plot.getTitle(), "My plot");
    }

    TEST(DefaultSize)
    {
        Aquila::TextPlot plot;
        CHECK_EQUAL(plot.getWidth(), 64u);
        CHECK_EQUAL(plot.getHeight(), 16u);
    }

    TEST(CustomSize)
    {
        Aquila::TextPlot plot;
        plot.setSize(80, 12);
        CHECK_EQUAL(plot.getWidth(), 80u);
        CHECK_EQUAL(plot.getHeight(), 12u);
    }

    TEST(PlotSineWave)
    {
        Aquila::SineGenerator generator(128);
        generator.setAmplitude(1).setFrequency(8).generate(64);
        std::stringstream out;
        Aquila::TextPlot plot("Data plot", out);
        auto expectedOutput =
            "\nData plot\n"
            "   ***             ***             ***             ***          \n"
            "                                                                \n"
            "  *   *           *   *           *   *           *   *         \n"
            "                                                                \n"
            " *     *         *     *         *     *         *     *        \n"
            "                                                                \n"
            "                                                                \n"
            "        *               *               *               *       \n"
            "*               *               *               *               \n"
            "                                                                \n"
            "                                                                \n"
            "         *     *         *     *         *     *         *     *\n"
            "                                                                \n"
            "          *   *           *   *           *   *           *   * \n"
            "                                                                \n"
            "           ***             ***             ***             ***  \n";

        plot.plot(generator);
        CHECK_EQUAL(expectedOutput, out.str());
    }
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: mitkPropertyManager.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision: 1.12 $

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

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

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

#include "mitkPaintbrushTool.h"

#include "mitkToolManager.h"
#include "mitkOverwriteSliceImageFilter.h"
#include "mitkBaseRenderer.h"
#include "ipSegmentation.h"

int mitk::PaintbrushTool::m_Size = 10;

mitk::PaintbrushTool::PaintbrushTool(int paintingPixelValue)
:FeedbackContourTool("PressMoveReleaseWithCTRLInversion"),
 m_PaintingPixelValue(paintingPixelValue)
{
}

mitk::PaintbrushTool::~PaintbrushTool()
{
}

void mitk::PaintbrushTool::Activated()
{
  Superclass::Activated();
  SizeChanged.Send(m_Size);
}

void mitk::PaintbrushTool::Deactivated()
{
  Superclass::Deactivated();
}

void mitk::PaintbrushTool::SetSize(int value)
{
  m_Size = value;
}

void mitk::PaintbrushTool::UpdateContour(const StateEvent* stateEvent)
{
  // examine stateEvent and create a contour that matches the pixel mask that we are going to draw
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return;

  Image::Pointer m_WorkingSlice = FeedbackContourTool::GetAffectedWorkingSlice( positionEvent );
  if (m_WorkingSlice.IsNull()) return;
  // create a copy of this slice (at least match the pixel sizes/spacings),
  // then draw the desired mask on it and create a contour from it

  // Convert to ipMITKSegmentationTYPE (because getting pixels relys on that data type)
  itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage;
  CastToItkImage( m_WorkingSlice, correctPixelTypeImage );
  assert (correctPixelTypeImage.IsNotNull() );

  itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection;
  imageDirection.SetIdentity();
  correctPixelTypeImage->SetDirection(imageDirection);

  Image::Pointer temporarySlice = Image::New();
  CastToMitkImage( correctPixelTypeImage, temporarySlice );

  ipPicDescriptor* stupidClone = ipPicClone( temporarySlice->GetSliceData()->GetPicDescriptor() );
  unsigned int pixelWidth  = m_Size + 1;
  unsigned int pixelHeight = m_Size + 1;

  if ( stupidClone->n[0] <= pixelWidth || stupidClone->n[1] <= pixelHeight )
  {
    std::cout << "Brush size is bigger than your working image. Reconsider this...\n"
                 "(Or tell your progammer until (s)he fixes this message.)" << std::endl;
    ipPicFree( stupidClone );
    return;
  }

  unsigned int lineLength( stupidClone->n[0] );
  unsigned int oneContourOffset(0);
  float circleCenterX = (float)m_Size / 2.0;
  float circleCenterY = (float)m_Size / 2.0;
  for (unsigned int x = 0; x <= pixelWidth; ++x)
    for (unsigned int y = 0; y <= pixelHeight; ++y)
    {
      unsigned int offset = lineLength * y + x;
      ipMITKSegmentationTYPE* current = (ipMITKSegmentationTYPE*)stupidClone->data + offset;

      float pixelCenterX = x + 0.5;
      float pixelCenterY = y + 0.5;

      float xoff = pixelCenterX - circleCenterX;
      float yoff = pixelCenterY - circleCenterY;

      bool inside = xoff * xoff + yoff * yoff < (m_Size * m_Size) / 4.0; // no idea, if this would work for ellipses
      if (inside)
      {
        *current = 1;
        oneContourOffset = offset;
      }
      else
      {
        *current = 0;
      }
    }

  int numberOfContourPoints( 0 );
  int newBufferSize( 0 );
  float* contourPoints = ipMITKSegmentationGetContour8N( stupidClone, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
  if (!contourPoints)
  {
    ipPicFree( stupidClone );
    return;
  }

  // copy point from float* to mitk::Contour
  Contour::Pointer contourInImageIndexCoordinates = Contour::New();
  contourInImageIndexCoordinates->Initialize();
  Point3D newPoint;
  for (int index = 0; index < numberOfContourPoints; ++index)
  {
    newPoint[0] = contourPoints[ 2 * index + 0 ] - circleCenterX; // master contour should be centered around (0,0)
    newPoint[1] = contourPoints[ 2 * index + 1] - circleCenterY;
    newPoint[2] = 0;

    contourInImageIndexCoordinates->AddVertex( newPoint );
  }

  free(contourPoints);

  m_MasterContour = FeedbackContourTool::BackProjectContourFrom2DSlice( m_WorkingSlice, contourInImageIndexCoordinates, true );   // true: sub 0.5 for ipSegmentation correctio

  ipPicFree( stupidClone );
}

/**
  Just show the contour, get one point as the central point and add surrounding points to the contour.
  */
bool mitk::PaintbrushTool::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  if (FeedbackContourTool::OnMousePressed( action, stateEvent ))
  {
    const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
    if (positionEvent)
    {
      UpdateContour( stateEvent );
    }
  }

  this->OnMouseMoved(action, stateEvent);

  FeedbackContourTool::SetFeedbackContourVisible(true);

  return true;
}

/**
  Insert the point to the feedback contour,finish to build the contour and at the same time the painting function
  */
bool mitk::PaintbrushTool::OnMouseMoved   (Action* action, const StateEvent* stateEvent)
{
  if (!FeedbackContourTool::OnMouseMoved( action, stateEvent )) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  DataTreeNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  int affectedDimension( -1 );
  int affectedSlice( -1 );
  if ( SegTool2D::DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) )
  {
    // copy the master contour, but center it around current pixel
    Contour* contour = FeedbackContourTool::GetFeedbackContour();
    contour->Initialize();

    Point3D pos = positionEvent->GetWorldPosition();
    for (unsigned int index = 0; index < m_MasterContour->GetNumberOfPoints(); ++index)
    {
      Point3D point = m_MasterContour->GetPoints()->ElementAt(index);
      switch(affectedDimension)
      {
        case 2:
          point[0] += pos[0] + image->GetGeometry()->GetSpacing()[0] / 2.0; /* plus half a pixel's spacing */
          point[1] += pos[1] + image->GetGeometry()->GetSpacing()[1] / 2.0;
          break;
        case 1:
          point[0] += pos[0] + image->GetGeometry()->GetSpacing()[0] / 2.0;
          point[2] += pos[2] + image->GetGeometry()->GetSpacing()[2] / 2.0;
          break;
        case 0:
          point[1] += pos[1] + image->GetGeometry()->GetSpacing()[1] / 2.0;
          point[2] += pos[2] + image->GetGeometry()->GetSpacing()[2] / 2.0;
          break;
      }

      contour->AddVertex( point );
    }

    Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image );

    if ( slice.IsNull() ) return false;

    Contour* feedbackContour( FeedbackContourTool::GetFeedbackContour() );
    Contour::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, true, false );

    if (projectedContour.IsNull()) return false;

    FeedbackContourTool::FillContourInSlice( projectedContour, slice, m_PaintingPixelValue );

    OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New();
    slicewriter->SetInput( image );
    slicewriter->SetCreateUndoInformation( true );
    slicewriter->SetSliceImage( slice );
    slicewriter->SetSliceDimension( affectedDimension );
    slicewriter->SetSliceIndex( affectedSlice );
    slicewriter->SetTimeStep( positionEvent->GetSender()->GetTimeStep( image ) );
    slicewriter->Update();

    assert( positionEvent->GetSender()->GetRenderWindow() );

    RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
  }

  return true;
}

bool mitk::PaintbrushTool::OnMouseReleased(Action* /*action*/, const StateEvent* /*stateEvent*/)
{
  FeedbackContourTool::SetFeedbackContourVisible(false);

  return true;
}

/**
  Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0.
  */
bool mitk::PaintbrushTool::OnInvertLogic(Action* action, const StateEvent* stateEvent)
{
  if (!FeedbackContourTool::OnInvertLogic(action, stateEvent)) return false;

  // Inversion only for 0 and 1 as painting values
  if (m_PaintingPixelValue == 1)
  {
    m_PaintingPixelValue = 0;
    FeedbackContourTool::SetFeedbackContourColor( 1.0, 0.0, 0.0 );
  }
  else if (m_PaintingPixelValue == 0)
  {
    m_PaintingPixelValue = 1;
    FeedbackContourTool::SetFeedbackContourColorDefault();
  }

  return true;
}

<commit_msg>FIX (#737): Paintbrush tool for InteractiveSegmentation<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: mitkPropertyManager.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision: 1.12 $

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

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

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

#include "mitkPaintbrushTool.h"

#include "mitkToolManager.h"
#include "mitkOverwriteSliceImageFilter.h"
#include "mitkBaseRenderer.h"
#include "ipSegmentation.h"

#define ROUND(a)     ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a)))

int mitk::PaintbrushTool::m_Size = 10;

mitk::PaintbrushTool::PaintbrushTool(int paintingPixelValue)
:FeedbackContourTool("PressMoveReleaseWithCTRLInversion"),
 m_PaintingPixelValue(paintingPixelValue)
{
}

mitk::PaintbrushTool::~PaintbrushTool()
{
}

void mitk::PaintbrushTool::Activated()
{
  Superclass::Activated();
  SizeChanged.Send(m_Size);
}

void mitk::PaintbrushTool::Deactivated()
{
  Superclass::Deactivated();
}

void mitk::PaintbrushTool::SetSize(int value)
{
  m_Size = value;
}

void mitk::PaintbrushTool::UpdateContour(const StateEvent* stateEvent)
{
  // examine stateEvent and create a contour that matches the pixel mask that we are going to draw
  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return;

  Image::Pointer m_WorkingSlice = FeedbackContourTool::GetAffectedWorkingSlice( positionEvent );
  if (m_WorkingSlice.IsNull()) return;
  // create a copy of this slice (at least match the pixel sizes/spacings),
  // then draw the desired mask on it and create a contour from it

  // Convert to ipMITKSegmentationTYPE (because getting pixels relys on that data type)
  itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage;
  CastToItkImage( m_WorkingSlice, correctPixelTypeImage );
  assert (correctPixelTypeImage.IsNotNull() );

  itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection;
  imageDirection.SetIdentity();
  correctPixelTypeImage->SetDirection(imageDirection);

  Image::Pointer temporarySlice = Image::New();
  CastToMitkImage( correctPixelTypeImage, temporarySlice );

  ipPicDescriptor* stupidClone = ipPicClone( temporarySlice->GetSliceData()->GetPicDescriptor() );
  unsigned int pixelWidth  = m_Size + 1;
  unsigned int pixelHeight = m_Size + 1;

  if ( stupidClone->n[0] <= pixelWidth || stupidClone->n[1] <= pixelHeight )
  {
    std::cout << "Brush size is bigger than your working image. Reconsider this...\n"
                 "(Or tell your progammer until (s)he fixes this message.)" << std::endl;
    ipPicFree( stupidClone );
    return;
  }

  unsigned int lineLength( stupidClone->n[0] );
  unsigned int oneContourOffset(0);
  float circleCenterX = (float)m_Size / 2.0;
  float circleCenterY = (float)m_Size / 2.0;
  for (unsigned int x = 0; x <= pixelWidth; ++x)
    for (unsigned int y = 0; y <= pixelHeight; ++y)
    {
      unsigned int offset = lineLength * y + x;
      ipMITKSegmentationTYPE* current = (ipMITKSegmentationTYPE*)stupidClone->data + offset;

      float pixelCenterX = x + 0.5;
      float pixelCenterY = y + 0.5;

      float xoff = pixelCenterX - circleCenterX;
      float yoff = pixelCenterY - circleCenterY;

      bool inside = xoff * xoff + yoff * yoff < (m_Size * m_Size) / 4.0; // no idea, if this would work for ellipses
      if (inside)
      {
        *current = 1;
        oneContourOffset = offset;
      }
      else
      {
        *current = 0;
      }
    }

  int numberOfContourPoints( 0 );
  int newBufferSize( 0 );
  float* contourPoints = ipMITKSegmentationGetContour8N( stupidClone, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
  if (!contourPoints)
  {
    ipPicFree( stupidClone );
    return;
  }

  // copy point from float* to mitk::Contour
  Contour::Pointer contourInImageIndexCoordinates = Contour::New();
  contourInImageIndexCoordinates->Initialize();
  Point3D newPoint;
  for (int index = 0; index < numberOfContourPoints; ++index)
  {
    newPoint[0] = contourPoints[ 2 * index + 0 ] - circleCenterX; // master contour should be centered around (0,0)
    newPoint[1] = contourPoints[ 2 * index + 1] - circleCenterY;
    newPoint[2] = 0;
    //std::cout << "(" << newPoint[0] << ", " << newPoint[1] << ")" << std::endl;

    contourInImageIndexCoordinates->AddVertex( newPoint );
  }

  free(contourPoints);

  m_MasterContour = FeedbackContourTool::BackProjectContourFrom2DSlice( m_WorkingSlice, contourInImageIndexCoordinates, true );   // true: sub 0.5 for ipSegmentation correction

  ipPicFree( stupidClone );
}

/**
  Just show the contour, get one point as the central point and add surrounding points to the contour.
  */
bool mitk::PaintbrushTool::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  if (FeedbackContourTool::OnMousePressed( action, stateEvent ))
  {
    const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
    if (positionEvent)
    {
      UpdateContour( stateEvent );
    }
  }

  this->OnMouseMoved(action, stateEvent);

  FeedbackContourTool::SetFeedbackContourVisible(true);

  return true;
}

/**
  Insert the point to the feedback contour,finish to build the contour and at the same time the painting function
  */
bool mitk::PaintbrushTool::OnMouseMoved   (Action* action, const StateEvent* stateEvent)
{
  if (!FeedbackContourTool::OnMouseMoved( action, stateEvent )) return false;
  if ( m_MasterContour.IsNull() || m_MasterContour->GetNumberOfPoints() == 0 ) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  DataTreeNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  int affectedDimension( -1 );
  int affectedSlice( -1 );
  if ( SegTool2D::DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) )
  {
    Point3D pos = positionEvent->GetWorldPosition() - image->GetGeometry()->GetOrigin().GetVectorFromOrigin();

    // round mouse cursor position to the nearest pixel center
    switch(affectedDimension)
    {
      case 2:
        pos[0] = ROUND(pos[0] / image->GetGeometry()->GetSpacing()[0]) * image->GetGeometry()->GetSpacing()[0];
        pos[1] = ROUND(pos[1] / image->GetGeometry()->GetSpacing()[1]) * image->GetGeometry()->GetSpacing()[1];
        break;
      case 1:
        pos[0] = ROUND(pos[0] / image->GetGeometry()->GetSpacing()[0]) * image->GetGeometry()->GetSpacing()[0];
        pos[2] = ROUND(pos[2] / image->GetGeometry()->GetSpacing()[2]) * image->GetGeometry()->GetSpacing()[2];
        break;
      case 0:
        pos[1] = ROUND(pos[1] / image->GetGeometry()->GetSpacing()[1]) * image->GetGeometry()->GetSpacing()[1];
        pos[2] = ROUND(pos[2] / image->GetGeometry()->GetSpacing()[2]) * image->GetGeometry()->GetSpacing()[2];
        break;
    }

    // Remember last value of pos; if this hasn't changed here, abort! This reduces the number of painting operations
    static Point3D lastPos; // uninitialized: if somebody finds out how this can be initialized in a one-liner, tell me
    if ( fabs(pos[0] - lastPos[0]) > mitk::eps ||
         fabs(pos[1] - lastPos[1]) > mitk::eps ||
         fabs(pos[2] - lastPos[2]) > mitk::eps )
     {
       lastPos = pos;
       //std::cout << "paint" << std::endl;
     }
     else
     {
       //std::cout << "." << std::flush;
       return false;
     }

    // copy the master contour, but center it around current pixel
    Contour* contour = FeedbackContourTool::GetFeedbackContour();
    contour->Initialize();
    for (unsigned int index = 0; index < m_MasterContour->GetNumberOfPoints(); ++index)
    {
      Point3D point = m_MasterContour->GetPoints()->ElementAt(index);
      switch(affectedDimension)
      {
        case 2:
          point[0] += pos[0];
          point[1] += pos[1];
          break;
        case 1:
          point[0] += pos[0];
          point[2] += pos[2];
          break;
        case 0:
          point[1] += pos[1];
          point[2] += pos[2];
          break;
      }

      if (m_Size % 2 != 0)
      {
        switch(affectedDimension)
        {
          case 2:
            point[0] +=image->GetGeometry()->GetSpacing()[0] / 2.0; /* plus half a pixel's spacing */
            point[1] +=image->GetGeometry()->GetSpacing()[1] / 2.0;
            break;
          case 1:
            point[0] +=image->GetGeometry()->GetSpacing()[0] / 2.0; /* plus half a pixel's spacing */
            point[2] +=image->GetGeometry()->GetSpacing()[2] / 2.0;
            break;
          case 0:
            point[1] +=image->GetGeometry()->GetSpacing()[1] / 2.0;
            point[2] +=image->GetGeometry()->GetSpacing()[2] / 2.0; /* plus half a pixel's spacing */
            break;
        }
      }

      contour->AddVertex( point );
    }

    Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image );

    if ( slice.IsNull() ) return false;

    Contour* feedbackContour( FeedbackContourTool::GetFeedbackContour() );
    Contour::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, true, false );

    if (projectedContour.IsNull()) return false;

    FeedbackContourTool::FillContourInSlice( projectedContour, slice, m_PaintingPixelValue );

    OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New();
    slicewriter->SetInput( image );
    slicewriter->SetCreateUndoInformation( true );
    slicewriter->SetSliceImage( slice );
    slicewriter->SetSliceDimension( affectedDimension );
    slicewriter->SetSliceIndex( affectedSlice );
    slicewriter->SetTimeStep( positionEvent->GetSender()->GetTimeStep( image ) );
    slicewriter->Update();

    assert( positionEvent->GetSender()->GetRenderWindow() );

    RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
  }

  return true;
}

bool mitk::PaintbrushTool::OnMouseReleased(Action* /*action*/, const StateEvent* /*stateEvent*/)
{
  FeedbackContourTool::SetFeedbackContourVisible(false);

  return true;
}

/**
  Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0.
  */
bool mitk::PaintbrushTool::OnInvertLogic(Action* action, const StateEvent* stateEvent)
{
  if (!FeedbackContourTool::OnInvertLogic(action, stateEvent)) return false;

  // Inversion only for 0 and 1 as painting values
  if (m_PaintingPixelValue == 1)
  {
    m_PaintingPixelValue = 0;
    FeedbackContourTool::SetFeedbackContourColor( 1.0, 0.0, 0.0 );
  }
  else if (m_PaintingPixelValue == 0)
  {
    m_PaintingPixelValue = 1;
    FeedbackContourTool::SetFeedbackContourColorDefault();
  }

  return true;
}

<|endoftext|>


<commit_before>#include "CpuRaytracingCharacter.h"

#include <CellarWorkbench/Misc/CellarUtils.h>
using namespace cellar;

#include <PropRoom2D/PropTeam/AbstractPropTeam.h>
#include <PropRoom2D/Hud/TextHud.h>
using namespace prop2;

#include <PropRoom3D/Team/AbstractTeam.h>
#include <PropRoom3D/Prop/Prop.h>
#include <PropRoom3D/Prop/Volume/Sphere.h>
#include <PropRoom3D/Prop/Volume/Plane.h>
#include <PropRoom3D/Prop/Costume/Glass.h>
#include <PropRoom3D/Prop/Costume/Chrome.h>
#include <PropRoom3D/Prop/Costume/FlatPaint.h>
#include <PropRoom3D/Prop/Costume/TexturedPaint.h>
using namespace prop3;

#include <Scaena/Stage/AbstractStage.h>
#include <Scaena/Stage/Event/StageTime.h>
using namespace scaena;

CpuRaytracingCharacter::CpuRaytracingCharacter(AbstractStage &stage) :
    AbstractCharacter(stage, "CPU Raytracing Character")
{
}

void CpuRaytracingCharacter::enterStage()
{
    _fps = stage().propTeam2D().createTextHud();
    _fps->setText("FPS: ");
    _fps->setHandlePosition(glm::dvec2(18.0, -30.0));
    _fps->setHorizontalAnchor(EHorizontalAnchor::LEFT);
    _fps->setVerticalAnchor(EVerticalAnchor::TOP);
    _fps->setHeight(20);
    _fps->setIsVisible(false);

    _ups = stage().propTeam2D().createTextHud();
    _ups->setText("UPS: ");
    _ups->setHandlePosition(glm::dvec2(18.0, -50.0));
    _ups->setHorizontalAnchor(EHorizontalAnchor::LEFT);
    _ups->setVerticalAnchor(EVerticalAnchor::TOP);
    _ups->setHeight(20);
    _ups->setIsVisible(false);

    glm::dvec3 negLim(-20.0, -20.0, 0.0);
    glm::dvec3 posLim( 20.0,  20.0, 0.0);
    std::shared_ptr<Volume> xNeg(new PlaneGhost(glm::dvec3(-1, 0, 0), negLim));
    std::shared_ptr<Volume> xPos(new PlaneGhost(glm::dvec3( 1, 0, 0), posLim));
    std::shared_ptr<Volume> yNeg(new PlaneGhost(glm::dvec3( 0,-1, 0), negLim));
    std::shared_ptr<Volume> yPos(new PlaneGhost(glm::dvec3( 0, 1, 0), posLim));
    std::shared_ptr<Volume> zSoc(new Plane(glm::dvec3( 0, 0, 1), negLim));
    std::shared_ptr<Volume> socle = (zSoc & xNeg & xPos & yNeg & yPos);

    glm::dvec3 boxMin(-10.0, -10.0, 0.0);
    glm::dvec3 boxMax( 10.0,  10.0, 20.0);
    glm::dvec3 boxDia = boxMax - boxMin;
    std::shared_ptr<Volume> xBot(new Plane(glm::dvec3(-1,  0,  0), boxMin));
    std::shared_ptr<Volume> xTop(new Plane(glm::dvec3( 1,  0,  0), boxMax));
    std::shared_ptr<Volume> yTop(new Plane(glm::dvec3( 0,  1,  0), boxMax));
    std::shared_ptr<Volume> zTop(new Plane(glm::dvec3( 0,  0,  1), boxMax));
    std::shared_ptr<Volume> yBot(new PlaneTexture(
        glm::dvec3( 0, -1,  0), boxMin,
        glm::dvec3(boxDia.x, 0, 0),
        glm::dvec3(0, 0, boxDia.z),
        boxMin));
    std::shared_ptr<Volume> box = (xBot & yBot & xTop & yTop & zTop);

    glm::dvec3 thickness = glm::dvec3(0.5);
    glm::dvec3 boxCenter = glm::dvec3(0, 0, 10);
    glm::dvec3 pillard(boxMax.x, boxMin.y, boxMin.z);
    std::shared_ptr<Volume> xPlane(new Plane(glm::dvec3(1, 0, 0), boxCenter));
    std::shared_ptr<Volume> zPlane(new Plane(glm::dvec3(0, 0, 1), boxCenter));
    std::shared_ptr<Volume> roof(new Plane(glm::dvec3( 0, 0, -1), boxMax - thickness));
    std::shared_ptr<Volume> pillarX(new Plane(glm::dvec3(-1, 0, 0), pillard - thickness));
    std::shared_ptr<Volume> pillarY(new Plane(glm::dvec3( 0, 1, 0), pillard + thickness));
    std::shared_ptr<Volume> yPlane(new PlaneTexture(
       glm::dvec3( 0, -1, 0), boxCenter,
       glm::dvec3(boxDia.x, 0, 0),
       glm::dvec3(0, 0, boxDia.z),
       boxMin));
    std::shared_ptr<Volume> rearWall(new PlaneTexture(
       glm::dvec3( 0, -1, 0), boxMax - thickness,
       glm::dvec3(boxDia.x, 0, 0),
       glm::dvec3(0, 0, boxDia.z),
       boxMin));

    std::shared_ptr<Volume> crop =
        (rearWall | roof | (pillarX & pillarY) | xPlane | (yPlane & zPlane));

    std::shared_ptr<Volume> chromeBallSphere(
                new Sphere(glm::dvec3(5.0, -5.0, -8.0) + boxCenter, 2.0));
    std::shared_ptr<Volume> glassBallSphere =
        std::shared_ptr<Volume>(new Sphere(glm::dvec3(5.0, 2.0, 4.0) + boxCenter, 4.0)) &
        std::shared_ptr<Volume>(new Sphere(glm::dvec3(5.0, 8.0, 4.0) + boxCenter, 4.0));

    std::shared_ptr<prop3::Costume> wallsCostume(
                new TexturedPaint(":/CpuRaytracing/Fusion_Albums.png",
                                  glm::dvec3(0.4, 0.4, 0.4)));
    std::shared_ptr<prop3::Costume> glassBallCostume(
                new Glass());
    std::shared_ptr<prop3::Costume> chromeBallCostume(
                new Chrome(glm::dvec3(212, 175, 55) / 255.0));

    _walls = stage().propTeam3D().createProp();
    _walls->setVolume(socle | (box & crop));
    _walls->setCostume(wallsCostume);

    _glassLens = stage().propTeam3D().createProp();
    _glassLens->setVolume(glassBallSphere);
    _glassLens->setCostume(glassBallCostume);

    _chromeBall = stage().propTeam3D().createProp();
    _chromeBall->setVolume(chromeBallSphere);
    _chromeBall->setCostume(chromeBallCostume);
}

void CpuRaytracingCharacter::beginStep(const StageTime &time)
{
    _ups->setText("UPS: " + toString(floor(1.0 / time.elapsedTime())));
}

void CpuRaytracingCharacter::draw(const StageTime &time)
{
    _fps->setText("FPS: " + toString(floor(1.0 / time.elapsedTime())));
}

void CpuRaytracingCharacter::exitStage()
{
    stage().propTeam2D().deleteTextHud(_fps);
    stage().propTeam2D().deleteTextHud(_ups);
}
<commit_msg>Lens moved and camera control added<commit_after>#include "CpuRaytracingCharacter.h"

#include <GLM/gtc/matrix_transform.hpp>

#include <CellarWorkbench/Misc/CellarUtils.h>
using namespace cellar;

#include <MediaWorkbench/Camera/Camera.h>
using namespace media;

#include <PropRoom2D/PropTeam/AbstractPropTeam.h>
#include <PropRoom2D/Hud/TextHud.h>
using namespace prop2;

#include <PropRoom3D/Team/AbstractTeam.h>
#include <PropRoom3D/Prop/Prop.h>
#include <PropRoom3D/Prop/Volume/Sphere.h>
#include <PropRoom3D/Prop/Volume/Plane.h>
#include <PropRoom3D/Prop/Costume/Glass.h>
#include <PropRoom3D/Prop/Costume/Chrome.h>
#include <PropRoom3D/Prop/Costume/FlatPaint.h>
#include <PropRoom3D/Prop/Costume/TexturedPaint.h>
using namespace prop3;

#include <Scaena/Stage/AbstractStage.h>
#include <Scaena/Stage/Event/StageTime.h>
using namespace scaena;

CpuRaytracingCharacter::CpuRaytracingCharacter(AbstractStage &stage) :
    AbstractCharacter(stage, "CPU Raytracing Character")
{
}

void CpuRaytracingCharacter::enterStage()
{
    _fps = stage().propTeam2D().createTextHud();
    _fps->setText("FPS: ");
    _fps->setHandlePosition(glm::dvec2(18.0, -30.0));
    _fps->setHorizontalAnchor(EHorizontalAnchor::LEFT);
    _fps->setVerticalAnchor(EVerticalAnchor::TOP);
    _fps->setHeight(20);
    _fps->setIsVisible(false);

    _ups = stage().propTeam2D().createTextHud();
    _ups->setText("UPS: ");
    _ups->setHandlePosition(glm::dvec2(18.0, -50.0));
    _ups->setHorizontalAnchor(EHorizontalAnchor::LEFT);
    _ups->setVerticalAnchor(EVerticalAnchor::TOP);
    _ups->setHeight(20);
    _ups->setIsVisible(false);

    // Setup Camera
    glm::dvec3 focusPos = glm::dvec3(-1.2, -1.2, 5.25);
    glm::dvec3 camPos = focusPos + glm::dvec3(25, -40, 14) * 2.0;

    glm::dvec3 upVec(0, 0, 1);
    glm::dvec3 frontVec = glm::normalize(focusPos - camPos);
    glm::dvec3 rightVec = glm::normalize(glm::cross(frontVec, upVec));

    stage().camera().updateView(glm::lookAt(camPos, focusPos, upVec));
    stage().camera().updateProjection(
        glm::perspectiveFov(
          glm::pi<double>() / 9.0,
          (double) stage().width(),
          (double) stage().height(),
          1.0, 2.0));

    glm::dvec3 negLim(-20.0, -20.0, 0.0);
    glm::dvec3 posLim( 20.0,  20.0, 0.0);
    std::shared_ptr<Volume> xNeg(new PlaneGhost(glm::dvec3(-1, 0, 0), negLim));
    std::shared_ptr<Volume> xPos(new PlaneGhost(glm::dvec3( 1, 0, 0), posLim));
    std::shared_ptr<Volume> yNeg(new PlaneGhost(glm::dvec3( 0,-1, 0), negLim));
    std::shared_ptr<Volume> yPos(new PlaneGhost(glm::dvec3( 0, 1, 0), posLim));
    std::shared_ptr<Volume> zSoc(new Plane(glm::dvec3( 0, 0, 1), negLim));
    std::shared_ptr<Volume> socle = (zSoc & xNeg & xPos & yNeg & yPos);

    glm::dvec3 boxMin(-10.0, -10.0, 0.0);
    glm::dvec3 boxMax( 10.0,  10.0, 20.0);
    glm::dvec3 boxDia = boxMax - boxMin;
    std::shared_ptr<Volume> xBot(new Plane(glm::dvec3(-1,  0,  0), boxMin));
    std::shared_ptr<Volume> xTop(new Plane(glm::dvec3( 1,  0,  0), boxMax));
    std::shared_ptr<Volume> yTop(new Plane(glm::dvec3( 0,  1,  0), boxMax));
    std::shared_ptr<Volume> zTop(new Plane(glm::dvec3( 0,  0,  1), boxMax));
    std::shared_ptr<Volume> yBot(new PlaneTexture(
        glm::dvec3( 0, -1,  0), boxMin,
        glm::dvec3(boxDia.x, 0, 0),
        glm::dvec3(0, 0, boxDia.z),
        boxMin));
    std::shared_ptr<Volume> box = (xBot & yBot & xTop & yTop & zTop);

    glm::dvec3 thickness = glm::dvec3(0.5);
    glm::dvec3 boxCenter = glm::dvec3(0, 0, 10);
    glm::dvec3 pillard(boxMax.x, boxMin.y, boxMin.z);
    std::shared_ptr<Volume> xPlane(new Plane(glm::dvec3(1, 0, 0), boxCenter));
    std::shared_ptr<Volume> zPlane(new Plane(glm::dvec3(0, 0, 1), boxCenter));
    std::shared_ptr<Volume> roof(new Plane(glm::dvec3( 0, 0, -1), boxMax - thickness));
    std::shared_ptr<Volume> pillarX(new Plane(glm::dvec3(-1, 0, 0), pillard - thickness));
    std::shared_ptr<Volume> pillarY(new Plane(glm::dvec3( 0, 1, 0), pillard + thickness));
    std::shared_ptr<Volume> yPlane(new PlaneTexture(
       glm::dvec3( 0, -1, 0), boxCenter,
       glm::dvec3(boxDia.x, 0, 0),
       glm::dvec3(0, 0, boxDia.z),
       boxMin));
    std::shared_ptr<Volume> rearWall(new PlaneTexture(
       glm::dvec3( 0, -1, 0), boxMax - thickness,
       glm::dvec3(boxDia.x, 0, 0),
       glm::dvec3(0, 0, boxDia.z),
       boxMin));

    std::shared_ptr<Volume> crop =
        (rearWall | roof | (pillarX & pillarY) | xPlane | (yPlane & zPlane));

    std::shared_ptr<Volume> chromeBallSphere(
                new Sphere(glm::dvec3(5.0, -5.0, 2), 2.0));
    std::shared_ptr<Volume> glassBallSphere =
        std::shared_ptr<Volume>(new Sphere(glm::dvec3(15, 3, 2), 4.0)) &
        std::shared_ptr<Volume>(new Sphere(glm::dvec3(15, -3, 2), 4.0));

    std::shared_ptr<prop3::Costume> wallsCostume(
                new TexturedPaint(":/CpuRaytracing/Fusion_Albums.png",
                                  glm::dvec3(0.4, 0.4, 0.4)));
    std::shared_ptr<prop3::Costume> glassBallCostume(
                new Glass());
    std::shared_ptr<prop3::Costume> chromeBallCostume(
                new Chrome(glm::dvec3(212, 175, 55) / 255.0));

    _walls = stage().propTeam3D().createProp();
    _walls->setVolume(socle | (box & crop));
    _walls->setCostume(wallsCostume);

    _glassLens = stage().propTeam3D().createProp();
    _glassLens->setVolume(glassBallSphere);
    _glassLens->setCostume(glassBallCostume);

    _chromeBall = stage().propTeam3D().createProp();
    _chromeBall->setVolume(chromeBallSphere);
    _chromeBall->setCostume(chromeBallCostume);
}

void CpuRaytracingCharacter::beginStep(const StageTime &time)
{
    _ups->setText("UPS: " + toString(floor(1.0 / time.elapsedTime())));
}

void CpuRaytracingCharacter::draw(const StageTime &time)
{
    _fps->setText("FPS: " + toString(floor(1.0 / time.elapsedTime())));
}

void CpuRaytracingCharacter::exitStage()
{
    stage().propTeam2D().deleteTextHud(_fps);
    stage().propTeam2D().deleteTextHud(_ups);
}
<|endoftext|>


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

// appleseed.foundation headers.
#include "foundation/math/fresnel.h"
#include "foundation/math/sss.h"
#include "foundation/math/rng/distribution.h"
#include "foundation/math/rng/mersennetwister.h"
#include "foundation/utility/test.h"

// Standard headers.
#include <cstddef>
#include <vector>

using namespace foundation;
using namespace std;

TEST_SUITE(Foundation_Math_SSS)
{
    static double rd_alpha_prime_roundtrip(
        const double rd,
        const double eta)
    {
        const double c1 = fresnel_moment_c1(eta);
        const double c2 = fresnel_moment_c2(eta);

        const double alpha_prime = compute_alpha_prime(rd, c1, c2);
        return compute_rd(alpha_prime, 2.0 * c1, 3.0 * c2);
    }

    TEST_CASE(Rd_AlphaPrime_Roundtrip)
    {
        EXPECT_FEQ_EPS(0.0, rd_alpha_prime_roundtrip(0.0, 1.6), 0.001);
        EXPECT_FEQ_EPS(0.1, rd_alpha_prime_roundtrip(0.1, 1.3), 0.001);
        EXPECT_FEQ_EPS(0.2, rd_alpha_prime_roundtrip(0.2, 1.2), 0.001);
        EXPECT_FEQ_EPS(0.4, rd_alpha_prime_roundtrip(0.4, 1.3), 0.001);
        EXPECT_FEQ_EPS(0.6, rd_alpha_prime_roundtrip(0.6, 1.4), 0.001);
        EXPECT_FEQ_EPS(0.8, rd_alpha_prime_roundtrip(0.8, 1.3), 0.001);
        EXPECT_FEQ_EPS(1.0, rd_alpha_prime_roundtrip(1.0, 1.5), 0.001);
    }

    static const double NormalizedDiffusionTestEps = 0.0001;

    TEST_CASE(NormalizedDiffusionA)
    {
        static const double Result[] =
        {
            4.68592, 4.11466, 3.77984, 3.60498, 3.52856, 3.5041, 3.50008,
            3.50002, 3.5024, 3.52074, 3.58352, 3.73426, 4.03144, 4.54858,
            5.37416, 6.6117, 8.37968, 10.8116, 14.056, 18.2763, 23.6511
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double s = normalized_diffusion_s(static_cast<double>(i) * 0.05);
            EXPECT_FEQ_EPS(Result[i], s, NormalizedDiffusionTestEps);
        }
    }

    TEST_CASE(NormalizedDiffusionR)
    {
        static const double Result[] =
        {
            2.53511, 0.674967, 0.327967, 0.192204, 0.124137, 0.0852575,
            0.0611367, 0.0452741, 0.0343737, 0.0266197, 0.0209473, 0.0167009,
            0.0134603, 0.0109471, 0.00897108, 0.00739936, 0.00613676, 0.00511384,
            0.00427902, 0.0035934, 0.00302721
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double r =
                normalized_diffusion_r(
                    static_cast<double>(i) * 0.1 + 0.05,
                    1.0,
                    3.583521,
                    0.5);

            EXPECT_FEQ_EPS(Result[i], r, NormalizedDiffusionTestEps);
        }
    }

    TEST_CASE(NormalizedDiffusionCdf)
    {
        static const double Result[] =
        {
            0.282838, 0.598244, 0.760091, 0.85267, 0.908478, 0.942885, 0.964293,
            0.97766, 0.98602, 0.99125, 0.994523, 0.996572, 0.997854, 0.998657,
            0.999159, 0.999474, 0.999671, 0.999794, 0.999871, 0.999919, 0.999949,
            0.999968, 0.99998, 0.999988, 0.999992, 0.999995, 0.999997, 0.999998,
            0.999999, 0.999999, 1
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double cdf =
                normalized_diffusion_cdf(
                    static_cast<double>(i) * 0.1 + 0.05,
                    14.056001,
                    1.0);

            EXPECT_FEQ_EPS(Result[i], cdf, NormalizedDiffusionTestEps);
        }
    }

    /*
    TEST_CASE(NormalizedDiffusionCdfPdf)
    {
        const double ndiff_step = 0.0001;

        MersenneTwister rng;

        for (size_t i = 0; i < 50; ++i)
        {
            const double a = rand_double1(rng);
            const double l = rand_double1(rng, 0.0001, 10.0);
            const double s = normalized_diffusion_s(a);
            const double r = rand_double1(rng, 0.0001, 20.0);

            const double pdf = normalized_diffusion_pdf(r, s, l);

            const double pdf_ndiff =
                (normalized_diffusion_cdf(r + ndiff_step, s, l) -
                 normalized_diffusion_cdf(r, s, l)) / ndiff_step;

            EXPECT_FEQ_EPS(pdf, pdf_ndiff, ndiff_step);
        }
    }
    */

    TEST_CASE(NormalizedDiffusionSample)
    {
        MersenneTwister rng;

        for (size_t i = 0; i < 50; ++i)
        {
            const double a = rand_double1(rng);
            const double l = rand_double1(rng, 0.001, 10.0);
            const double s = normalized_diffusion_s(a);
            const double e = rand_double1(rng);
            const double r = normalized_diffusion_sample(s, l, e);
            EXPECT_FEQ_EPS(e, normalized_diffusion_cdf(r, s, l), NormalizedDiffusionTestEps);
        }
    }
}
<commit_msg>reordered #include statements.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// appleseed.foundation headers.
#include "foundation/math/rng/distribution.h"
#include "foundation/math/rng/mersennetwister.h"
#include "foundation/math/fresnel.h"
#include "foundation/math/sss.h"
#include "foundation/utility/test.h"

// Standard headers.
#include <cstddef>
#include <vector>

using namespace foundation;
using namespace std;

TEST_SUITE(Foundation_Math_SSS)
{
    static double rd_alpha_prime_roundtrip(
        const double rd,
        const double eta)
    {
        const double c1 = fresnel_moment_c1(eta);
        const double c2 = fresnel_moment_c2(eta);

        const double alpha_prime = compute_alpha_prime(rd, c1, c2);
        return compute_rd(alpha_prime, 2.0 * c1, 3.0 * c2);
    }

    TEST_CASE(Rd_AlphaPrime_Roundtrip)
    {
        EXPECT_FEQ_EPS(0.0, rd_alpha_prime_roundtrip(0.0, 1.6), 0.001);
        EXPECT_FEQ_EPS(0.1, rd_alpha_prime_roundtrip(0.1, 1.3), 0.001);
        EXPECT_FEQ_EPS(0.2, rd_alpha_prime_roundtrip(0.2, 1.2), 0.001);
        EXPECT_FEQ_EPS(0.4, rd_alpha_prime_roundtrip(0.4, 1.3), 0.001);
        EXPECT_FEQ_EPS(0.6, rd_alpha_prime_roundtrip(0.6, 1.4), 0.001);
        EXPECT_FEQ_EPS(0.8, rd_alpha_prime_roundtrip(0.8, 1.3), 0.001);
        EXPECT_FEQ_EPS(1.0, rd_alpha_prime_roundtrip(1.0, 1.5), 0.001);
    }

    static const double NormalizedDiffusionTestEps = 0.0001;

    TEST_CASE(NormalizedDiffusionA)
    {
        static const double Result[] =
        {
            4.68592, 4.11466, 3.77984, 3.60498, 3.52856, 3.5041, 3.50008,
            3.50002, 3.5024, 3.52074, 3.58352, 3.73426, 4.03144, 4.54858,
            5.37416, 6.6117, 8.37968, 10.8116, 14.056, 18.2763, 23.6511
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double s = normalized_diffusion_s(static_cast<double>(i) * 0.05);
            EXPECT_FEQ_EPS(Result[i], s, NormalizedDiffusionTestEps);
        }
    }

    TEST_CASE(NormalizedDiffusionR)
    {
        static const double Result[] =
        {
            2.53511, 0.674967, 0.327967, 0.192204, 0.124137, 0.0852575,
            0.0611367, 0.0452741, 0.0343737, 0.0266197, 0.0209473, 0.0167009,
            0.0134603, 0.0109471, 0.00897108, 0.00739936, 0.00613676, 0.00511384,
            0.00427902, 0.0035934, 0.00302721
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double r =
                normalized_diffusion_r(
                    static_cast<double>(i) * 0.1 + 0.05,
                    1.0,
                    3.583521,
                    0.5);

            EXPECT_FEQ_EPS(Result[i], r, NormalizedDiffusionTestEps);
        }
    }

    TEST_CASE(NormalizedDiffusionCdf)
    {
        static const double Result[] =
        {
            0.282838, 0.598244, 0.760091, 0.85267, 0.908478, 0.942885, 0.964293,
            0.97766, 0.98602, 0.99125, 0.994523, 0.996572, 0.997854, 0.998657,
            0.999159, 0.999474, 0.999671, 0.999794, 0.999871, 0.999919, 0.999949,
            0.999968, 0.99998, 0.999988, 0.999992, 0.999995, 0.999997, 0.999998,
            0.999999, 0.999999, 1
        };

        for (size_t i = 0, e = countof(Result); i < e; ++i)
        {
            const double cdf =
                normalized_diffusion_cdf(
                    static_cast<double>(i) * 0.1 + 0.05,
                    14.056001,
                    1.0);

            EXPECT_FEQ_EPS(Result[i], cdf, NormalizedDiffusionTestEps);
        }
    }

    /*
    TEST_CASE(NormalizedDiffusionCdfPdf)
    {
        const double ndiff_step = 0.0001;

        MersenneTwister rng;

        for (size_t i = 0; i < 50; ++i)
        {
            const double a = rand_double1(rng);
            const double l = rand_double1(rng, 0.0001, 10.0);
            const double s = normalized_diffusion_s(a);
            const double r = rand_double1(rng, 0.0001, 20.0);

            const double pdf = normalized_diffusion_pdf(r, s, l);

            const double pdf_ndiff =
                (normalized_diffusion_cdf(r + ndiff_step, s, l) -
                 normalized_diffusion_cdf(r, s, l)) / ndiff_step;

            EXPECT_FEQ_EPS(pdf, pdf_ndiff, ndiff_step);
        }
    }
    */

    TEST_CASE(NormalizedDiffusionSample)
    {
        MersenneTwister rng;

        for (size_t i = 0; i < 50; ++i)
        {
            const double a = rand_double1(rng);
            const double l = rand_double1(rng, 0.001, 10.0);
            const double s = normalized_diffusion_s(a);
            const double e = rand_double1(rng);
            const double r = normalized_diffusion_sample(s, l, e);
            EXPECT_FEQ_EPS(e, normalized_diffusion_cdf(r, s, l), NormalizedDiffusionTestEps);
        }
    }
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 * expr_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include <unordered_map>

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "utils/lsyscache.h"
#include "executor/executor.h"
#include "parser/parsetree.h"

#include "backend/bridge/dml/tuple/tuple_transformer.h"
#include "backend/bridge/dml/expr/pg_func_map.h"
#include "backend/bridge/dml/expr/expr_transformer.h"
#include "backend/common/logger.h"
#include "backend/common/value.h"
#include "backend/common/value_factory.h"
#include "backend/expression/expression_util.h"

namespace peloton {
namespace bridge {

expression::AbstractExpression*
ReMapPgFunc(Oid pg_func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc);

extern std::unordered_map<Oid, peloton::ExpressionType> pg_func_map;

void ExprTransformer::PrintPostgressExprTree(const ExprState* expr_state,
                                             std::string prefix) {
  auto tag = nodeTag(expr_state->expr);

  /* TODO Not complete.
   * Not all ExprState has a child / children list,
   * so it would take some multiplexing to print it recursively here.
   */
  LOG_INFO("%u ", tag);
}

/**
 * @brief Transform a ExprState tree (Postgres) to a AbstractExpression tree (Peloton) recursively.
 */
expression::AbstractExpression* ExprTransformer::TransformExpr(
    const ExprState* expr_state) {

  if(!expr_state)
    return nullptr;

  /* Special case:
   * Input is a list of expressions.
   * Transform it to a conjunction tree.
   */
  if(expr_state->type == T_List) {
    return TransformList(expr_state);
  }

  expression::AbstractExpression* peloton_expr = nullptr;

  switch (nodeTag(expr_state->expr)) {
    case T_Const:
      peloton_expr = TransformConst(expr_state);
      break;

    case T_OpExpr:
      peloton_expr = TransformOp(expr_state);
      break;

    case T_Var:
      peloton_expr = TransformVar(expr_state);
      break;

    case T_BoolExpr:
      peloton_expr = TransformBool(expr_state);
      break;

    case T_Param:
      peloton_expr = TransformParam(expr_state);
      break;

    case T_RelabelType:
      peloton_expr = TransformRelabelType(expr_state);
      break;

    case T_FuncExpr:
      peloton_expr = TransformFunc(expr_state);
      break;

    default:
      LOG_ERROR("Unsupported Postgres Expr type: %u (see 'nodes.h')\n",
                nodeTag(expr_state->expr));
  }

  return peloton_expr;
}

bool ExprTransformer::CleanExprTree(expression::AbstractExpression* root) {

  // AbstractExpression's destructor already handles deleting children
  delete root;

  return true;
}

expression::AbstractExpression* ExprTransformer::TransformConst(
    const ExprState* es) {

  auto const_expr = reinterpret_cast<const Const*>(es->expr);

  Value value;

  if (const_expr->constisnull) {  // Constant is null
    value = ValueFactory::GetNullValue();
  }
  else if(const_expr->constbyval){  // non null
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else if(const_expr->constlen == -1) {
    LOG_INFO("Probably handing a string constant \n");
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else {
    LOG_ERROR("Unknown Const profile: constlen = %d , constbyval = %d, constvalue = %u \n",
              const_expr->constlen, const_expr->constbyval, const_expr->constvalue);
  }

  LOG_INFO("Const : ");
  std::cout << value << std::endl;

  // A Const Expr has no children.
  return expression::ConstantValueFactory(value);
}

expression::AbstractExpression* ExprTransformer::TransformOp(
    const ExprState* es) {

  LOG_INFO("Transform Op \n");

  auto op_expr = reinterpret_cast<const OpExpr*>(es->expr);
  auto func_state = reinterpret_cast<const FuncExprState*>(es);

  assert(op_expr->opfuncid != 0); // Hopefully it has been filled in by PG planner
  assert(list_length(func_state->args) <= 2);   // Hopefully it has at most two parameters

  expression::AbstractExpression* lc = nullptr;
  expression::AbstractExpression* rc = nullptr;

  // Add function arguments as children
  int i = 0;
  ListCell   *arg;
  foreach(arg, func_state->args)
  {
    ExprState  *argstate = (ExprState *) lfirst(arg);

    if(i == 0)
      lc = TransformExpr(argstate);
    else if(i == 1)
      rc = TransformExpr(argstate);
    else
      break; // skip >2 arguments

    i++;
  }

  return ReMapPgFunc(op_expr->opfuncid, lc, rc);
}

expression::AbstractExpression* ExprTransformer::TransformVar(
    const ExprState* es) {

  // Var expr only needs default ES
  auto var_expr = reinterpret_cast<const Var*>(es->expr);

  assert(var_expr->varattno != InvalidAttrNumber);

  oid_t tuple_idx = (var_expr->varno == INNER_VAR ? 1 : 0);  // Seems reasonable, c.f. ExecEvalScalarVarFast()
  oid_t value_idx = static_cast<oid_t>(var_expr->varattno - 1); // Damnit attno is 1-index

  LOG_INFO("tuple_idx = %u , value_idx = %u \n", tuple_idx, value_idx);

  // TupleValue expr has no children.
  return expression::TupleValueFactory(tuple_idx, value_idx);

}

expression::AbstractExpression* ExprTransformer::TransformBool(
    const ExprState* es) {

  auto bool_expr = reinterpret_cast<const BoolExpr*>(es->expr);
  auto bool_state = reinterpret_cast<const BoolExprState*>(es);

  auto bool_op = bool_expr->boolop;

  /*
   * AND and OR can take >=2 arguments,
   * while NOT should take only one.
   */
  assert(bool_state->args);
  assert(bool_op != NOT_EXPR || list_length(bool_state->args) == 1);
  assert(bool_op == NOT_EXPR || list_length(bool_state->args) >= 2);

  auto args = bool_state->args;

  switch(bool_op){

    case AND_EXPR:
      LOG_INFO("Bool AND list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_AND);

    case OR_EXPR:
      LOG_INFO("Bool OR list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_OR);

    case NOT_EXPR:
    {
      LOG_INFO("Bool NOT \n");
      auto child_es = reinterpret_cast<const ExprState*>(lfirst(list_head(args)));
      auto child = TransformExpr(child_es);
      return expression::OperatorFactory(EXPRESSION_TYPE_OPERATOR_NOT, child, nullptr);
    }

    default:
      LOG_ERROR("Unrecognized BoolExpr : %u", bool_op);
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformParam(const ExprState *es) {

  auto param_expr = reinterpret_cast<const Param*>(es->expr);

  switch (param_expr->paramkind) {
    case PARAM_EXTERN:
      LOG_INFO("Handle EXTREN PARAM");
      return expression::ParameterValueFactory(param_expr->paramid + 1); // 1 indexed
      break;
    default:
      LOG_ERROR("Unrecognized param kind %d", param_expr->paramkind);
      break;
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformRelabelType(const ExprState *es) {
  auto state = reinterpret_cast<const GenericExprState*>(es);
  auto expr = reinterpret_cast<const RelabelType *>(es->expr);
  auto child_state = state->arg;
  auto child_expr = expr->arg;

  assert(expr->xpr.type == T_RelabelType);

  LOG_INFO("child is of type %d, %d", child_expr->type, child_state->type);
  LOG_INFO("%d, %d", expr->resulttype, expr->relabelformat);
  expression::AbstractExpression *child = ExprTransformer::TransformExpr(child_state);

  //TODO: not implemented yet

  return child;
}

expression::AbstractExpression* ExprTransformer::TransformFunc(const ExprState *es) {
  auto state = reinterpret_cast<const FuncExprState*>(es);
  auto expr = reinterpret_cast<const FuncExpr*>(es->expr);
  auto expr_args = reinterpret_cast<const ExprState*>(state->args);

  assert(expr->xpr.type == T_FuncExpr);

  LOG_INFO("Return type: %d, isReturn %d, Coercion: %d", expr->funcresulttype, expr->funcretset, expr->funcformat);
  expression::AbstractExpression *args = ExprTransformer::TransformExpr(expr_args);
  LOG_INFO("args : %s", args->DebugInfo(" ").c_str());

  //TODO: not implemented yet

  return nullptr;

}

expression::AbstractExpression*
ExprTransformer::TransformList(const ExprState* es, ExpressionType et) {

  assert(et == EXPRESSION_TYPE_CONJUNCTION_AND || et == EXPRESSION_TYPE_CONJUNCTION_OR);

  const List* list = reinterpret_cast<const List*>(es);
  ListCell *l;
  int length = list_length(list);
  assert(length > 0);
  LOG_INFO("Expression List of length %d", length);
  std::list<expression::AbstractExpression*> exprs; // a list of AND'ed expressions

  foreach(l, list)
  {
    const ExprState *expr_state = reinterpret_cast<const ExprState*>(lfirst(l));
    exprs.push_back(ExprTransformer::TransformExpr(expr_state));
  }

  return expression::ConjunctionFactory(et, exprs);

}

/**
 * @brief Helper function: re-map Postgres's builtin function Oid
 * to proper expression type in Peloton
 *
 * @param pg_func_id  PG Function Id used to lookup function in \b fmrg_builtin[]
 * (see Postgres source file 'fmgrtab.cpp')
 * @param lc          Left child.
 * @param rc          Right child.
 * @return            Corresponding expression tree in peloton.
 */
expression::AbstractExpression*
ReMapPgFunc(Oid func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc) {

  auto itr = pg_func_map.find(func_id);

  if(itr == pg_func_map.end()){
    LOG_ERROR("Unsupported PG Function ID : %u (check fmgrtab.cpp)\n", func_id);
    return nullptr;
  }

  auto pl_expr_type = itr->second;

  switch(pl_expr_type){

    case EXPRESSION_TYPE_COMPARE_EQ:
    case EXPRESSION_TYPE_COMPARE_NE:
    case EXPRESSION_TYPE_COMPARE_GT:
    case EXPRESSION_TYPE_COMPARE_LT:
    case EXPRESSION_TYPE_COMPARE_GTE:
    case EXPRESSION_TYPE_COMPARE_LTE:
      return expression::ComparisonFactory(pl_expr_type, lc, rc);

    case EXPRESSION_TYPE_OPERATOR_PLUS:
    case EXPRESSION_TYPE_OPERATOR_MINUS:
    case EXPRESSION_TYPE_OPERATOR_MULTIPLY:
    case EXPRESSION_TYPE_OPERATOR_DIVIDE:
      return expression::OperatorFactory(pl_expr_type, lc, rc);

    default:
      LOG_ERROR("This Peloton ExpressionType is in our map but not transformed here : %u", pl_expr_type);
  }

  return nullptr;
}

}  // namespace bridge
}  // namespace peloton
<commit_msg>fix compilation<commit_after>/*-------------------------------------------------------------------------
 *
 * expr_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include <unordered_map>

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "utils/lsyscache.h"
#include "executor/executor.h"
#include "parser/parsetree.h"

#include "backend/bridge/dml/tuple/tuple_transformer.h"
#include "backend/bridge/dml/expr/pg_func_map.h"
#include "backend/bridge/dml/expr/expr_transformer.h"
#include "backend/common/logger.h"
#include "backend/common/value.h"
#include "backend/common/value_factory.h"
#include "backend/expression/expression_util.h"

namespace peloton {
namespace bridge {

expression::AbstractExpression*
ReMapPgFunc(Oid pg_func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc);

extern std::unordered_map<Oid, peloton::ExpressionType> pg_func_map;

void ExprTransformer::PrintPostgressExprTree(const ExprState* expr_state,
                                             std::string prefix) {
  auto tag = nodeTag(expr_state->expr);

  /* TODO Not complete.
   * Not all ExprState has a child / children list,
   * so it would take some multiplexing to print it recursively here.
   */
  LOG_INFO("%u ", tag);
}

/**
 * @brief Transform a ExprState tree (Postgres) to a AbstractExpression tree (Peloton) recursively.
 */
expression::AbstractExpression* ExprTransformer::TransformExpr(
    const ExprState* expr_state) {

  if(!expr_state)
    return nullptr;

  /* Special case:
   * Input is a list of expressions.
   * Transform it to a conjunction tree.
   */
  if(expr_state->type == T_List) {
    return TransformList(expr_state);
  }

  expression::AbstractExpression* peloton_expr = nullptr;

  switch (nodeTag(expr_state->expr)) {
    case T_Const:
      peloton_expr = TransformConst(expr_state);
      break;

    case T_OpExpr:
      peloton_expr = TransformOp(expr_state);
      break;

    case T_Var:
      peloton_expr = TransformVar(expr_state);
      break;

    case T_BoolExpr:
      peloton_expr = TransformBool(expr_state);
      break;

    case T_Param:
      peloton_expr = TransformParam(expr_state);
      break;

    case T_RelabelType:
      peloton_expr = TransformRelabelType(expr_state);
      break;

    case T_FuncExpr:
      peloton_expr = TransformFunc(expr_state);
      break;

    default:
      LOG_ERROR("Unsupported Postgres Expr type: %u (see 'nodes.h')\n",
                nodeTag(expr_state->expr));
  }

  return peloton_expr;
}

bool ExprTransformer::CleanExprTree(expression::AbstractExpression* root) {

  // AbstractExpression's destructor already handles deleting children
  delete root;

  return true;
}

expression::AbstractExpression* ExprTransformer::TransformConst(
    const ExprState* es) {

  auto const_expr = reinterpret_cast<const Const*>(es->expr);

  Value value;

  if (const_expr->constisnull) {  // Constant is null
    value = ValueFactory::GetNullValue();
  }
  else if(const_expr->constbyval){  // non null
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else if(const_expr->constlen == -1) {
    LOG_INFO("Probably handing a string constant \n");
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else {
    LOG_ERROR("Unknown Const profile: constlen = %d , constbyval = %d, constvalue = %lu \n",
              const_expr->constlen, const_expr->constbyval, (long unsigned)const_expr->constvalue);
  }

  LOG_INFO("Const : ");
  std::cout << value << std::endl;

  // A Const Expr has no children.
  return expression::ConstantValueFactory(value);
}

expression::AbstractExpression* ExprTransformer::TransformOp(
    const ExprState* es) {

  LOG_INFO("Transform Op \n");

  auto op_expr = reinterpret_cast<const OpExpr*>(es->expr);
  auto func_state = reinterpret_cast<const FuncExprState*>(es);

  assert(op_expr->opfuncid != 0); // Hopefully it has been filled in by PG planner
  assert(list_length(func_state->args) <= 2);   // Hopefully it has at most two parameters

  expression::AbstractExpression* lc = nullptr;
  expression::AbstractExpression* rc = nullptr;

  // Add function arguments as children
  int i = 0;
  ListCell   *arg;
  foreach(arg, func_state->args)
  {
    ExprState  *argstate = (ExprState *) lfirst(arg);

    if(i == 0)
      lc = TransformExpr(argstate);
    else if(i == 1)
      rc = TransformExpr(argstate);
    else
      break; // skip >2 arguments

    i++;
  }

  return ReMapPgFunc(op_expr->opfuncid, lc, rc);
}

expression::AbstractExpression* ExprTransformer::TransformVar(
    const ExprState* es) {

  // Var expr only needs default ES
  auto var_expr = reinterpret_cast<const Var*>(es->expr);

  assert(var_expr->varattno != InvalidAttrNumber);

  oid_t tuple_idx = (var_expr->varno == INNER_VAR ? 1 : 0);  // Seems reasonable, c.f. ExecEvalScalarVarFast()
  oid_t value_idx = static_cast<oid_t>(var_expr->varattno - 1); // Damnit attno is 1-index

  LOG_INFO("tuple_idx = %u , value_idx = %u \n", tuple_idx, value_idx);

  // TupleValue expr has no children.
  return expression::TupleValueFactory(tuple_idx, value_idx);

}

expression::AbstractExpression* ExprTransformer::TransformBool(
    const ExprState* es) {

  auto bool_expr = reinterpret_cast<const BoolExpr*>(es->expr);
  auto bool_state = reinterpret_cast<const BoolExprState*>(es);

  auto bool_op = bool_expr->boolop;

  /*
   * AND and OR can take >=2 arguments,
   * while NOT should take only one.
   */
  assert(bool_state->args);
  assert(bool_op != NOT_EXPR || list_length(bool_state->args) == 1);
  assert(bool_op == NOT_EXPR || list_length(bool_state->args) >= 2);

  auto args = bool_state->args;

  switch(bool_op){

    case AND_EXPR:
      LOG_INFO("Bool AND list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_AND);

    case OR_EXPR:
      LOG_INFO("Bool OR list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_OR);

    case NOT_EXPR:
    {
      LOG_INFO("Bool NOT \n");
      auto child_es = reinterpret_cast<const ExprState*>(lfirst(list_head(args)));
      auto child = TransformExpr(child_es);
      return expression::OperatorFactory(EXPRESSION_TYPE_OPERATOR_NOT, child, nullptr);
    }

    default:
      LOG_ERROR("Unrecognized BoolExpr : %u", bool_op);
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformParam(const ExprState *es) {

  auto param_expr = reinterpret_cast<const Param*>(es->expr);

  switch (param_expr->paramkind) {
    case PARAM_EXTERN:
      LOG_INFO("Handle EXTREN PARAM");
      return expression::ParameterValueFactory(param_expr->paramid + 1); // 1 indexed
      break;
    default:
      LOG_ERROR("Unrecognized param kind %d", param_expr->paramkind);
      break;
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformRelabelType(const ExprState *es) {
  auto state = reinterpret_cast<const GenericExprState*>(es);
  auto expr = reinterpret_cast<const RelabelType *>(es->expr);
  auto child_state = state->arg;
  auto child_expr = expr->arg;

  assert(expr->xpr.type == T_RelabelType);

  LOG_INFO("child is of type %d, %d", child_expr->type, child_state->type);
  LOG_INFO("%d, %d", expr->resulttype, expr->relabelformat);
  expression::AbstractExpression *child = ExprTransformer::TransformExpr(child_state);

  //TODO: not implemented yet

  return child;
}

expression::AbstractExpression* ExprTransformer::TransformFunc(const ExprState *es) {
  auto state = reinterpret_cast<const FuncExprState*>(es);
  auto expr = reinterpret_cast<const FuncExpr*>(es->expr);
  auto expr_args = reinterpret_cast<const ExprState*>(state->args);

  assert(expr->xpr.type == T_FuncExpr);

  LOG_INFO("Return type: %d, isReturn %d, Coercion: %d", expr->funcresulttype, expr->funcretset, expr->funcformat);
  expression::AbstractExpression *args = ExprTransformer::TransformExpr(expr_args);
  LOG_INFO("args : %s", args->DebugInfo(" ").c_str());

  //TODO: not implemented yet

  return nullptr;

}

expression::AbstractExpression*
ExprTransformer::TransformList(const ExprState* es, ExpressionType et) {

  assert(et == EXPRESSION_TYPE_CONJUNCTION_AND || et == EXPRESSION_TYPE_CONJUNCTION_OR);

  const List* list = reinterpret_cast<const List*>(es);
  ListCell *l;
  int length = list_length(list);
  assert(length > 0);
  LOG_INFO("Expression List of length %d", length);
  std::list<expression::AbstractExpression*> exprs; // a list of AND'ed expressions

  foreach(l, list)
  {
    const ExprState *expr_state = reinterpret_cast<const ExprState*>(lfirst(l));
    exprs.push_back(ExprTransformer::TransformExpr(expr_state));
  }

  return expression::ConjunctionFactory(et, exprs);

}

/**
 * @brief Helper function: re-map Postgres's builtin function Oid
 * to proper expression type in Peloton
 *
 * @param pg_func_id  PG Function Id used to lookup function in \b fmrg_builtin[]
 * (see Postgres source file 'fmgrtab.cpp')
 * @param lc          Left child.
 * @param rc          Right child.
 * @return            Corresponding expression tree in peloton.
 */
expression::AbstractExpression*
ReMapPgFunc(Oid func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc) {

  auto itr = pg_func_map.find(func_id);

  if(itr == pg_func_map.end()){
    LOG_ERROR("Unsupported PG Function ID : %u (check fmgrtab.cpp)\n", func_id);
    return nullptr;
  }

  auto pl_expr_type = itr->second;

  switch(pl_expr_type){

    case EXPRESSION_TYPE_COMPARE_EQ:
    case EXPRESSION_TYPE_COMPARE_NE:
    case EXPRESSION_TYPE_COMPARE_GT:
    case EXPRESSION_TYPE_COMPARE_LT:
    case EXPRESSION_TYPE_COMPARE_GTE:
    case EXPRESSION_TYPE_COMPARE_LTE:
      return expression::ComparisonFactory(pl_expr_type, lc, rc);

    case EXPRESSION_TYPE_OPERATOR_PLUS:
    case EXPRESSION_TYPE_OPERATOR_MINUS:
    case EXPRESSION_TYPE_OPERATOR_MULTIPLY:
    case EXPRESSION_TYPE_OPERATOR_DIVIDE:
      return expression::OperatorFactory(pl_expr_type, lc, rc);

    default:
      LOG_ERROR("This Peloton ExpressionType is in our map but not transformed here : %u", pl_expr_type);
  }

  return nullptr;
}

}  // namespace bridge
}  // namespace peloton
<|endoftext|>


<commit_before>#define WIN32_LEAN_AND_MEAN

#include <SDKDDKVer.h>
#include <windows.h>
#include "HookAPI.h"
#include "TeamSpeak.h"
#include <ws2tcpip.h>
#include <atomic>
#include <list>
#include <concurrent_queue.h>

#pragma comment (lib, "Ws2_32.lib")

// Default buffer length
#define BUFLEN 4096

// Socket used for TeamSpeak communication
std::atomic<SOCKET> client = NULL;
// Lua state used when requiring script files
std::atomic<lua_State *> state = NULL;
// Boolean telling the socket thread whether to keep the network loop running
std::atomic<bool> running = FALSE;
// Boolean telling if the TeamSpeak mod has been initialized
std::atomic<bool> initialized = TRUE;
// Queue of commands to be sent to the Lua script
Concurrency::concurrent_queue<String *> queue;
// Chat message history and its length and status
std::list<ChatMessage *> history;
unsigned int max_history = 20;
bool loading_history = false;

// Tries to connect to TeamSpeak using ClientQuery
// Returns a new socket or NULL on failure

SOCKET Connect(PCSTR hostname, PCSTR port)
{
	// Creates a structure used for containing the socket information
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) return NULL;

	// Creates a structure used for containing the connection information
	struct addrinfo *info, *ptr, hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	result = getaddrinfo(hostname, port, &hints, &info);
	if (result != 0)
	{
		WSACleanup();
		return NULL;
	}

	// Tries to connect to the specified address
	SOCKET client = INVALID_SOCKET;
	for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
	{
		client = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (client == INVALID_SOCKET)
		{
			WSACleanup();
			return NULL;
		}
		result = connect(client, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (result == SOCKET_ERROR)
		{
			closesocket(client);
			client = INVALID_SOCKET;
			continue;
		}
		break;
	}

	// Releases the address information strcuture from memory
	freeaddrinfo(info);

	// Return NULL if the connection could not be established
	if (client == INVALID_SOCKET)
	{
		WSACleanup();
		return NULL;
	}

	// Sets keep alive to true for the socket
	char value = 1;
	setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));

	return client;
}

// Socket thread
// Executes a loop reading messages and passing them to the Lua script

DWORD WINAPI Main(LPVOID param)
{
	int length;
	char buffer[BUFLEN];
	char *ptr, *context;
	const char *separator = "\n\r";
	const char *command = "clientnotifyregister schandlerid=0 event=any\n";

	// Starts the network loop
	for (running = true; running;)
	{
		// Connects to the local TeamSpeak ClientQuery and retries on failure
		client = Connect("127.0.0.1", "25639");
		if (client == NULL) continue;

		// Receives the initial ClientQuery headers
		for (int header = 182; header > 0; header -= length)
			length = recv(client, buffer, BUFLEN, 0);

		// Sends a "listen to all events" command and receives its response
		send(client, command, strlen(command), 0);
		recv(client, buffer, BUFLEN, 0);

		// Reads messages from the ClientQuery input stream
		do
		{
			// Receives a message and null terminates it
			buffer[length = recv(client, buffer, BUFLEN, 0)] = 0;
			// Splits up different messages that might be in the same buffer
			ptr = strtok_s(buffer, separator, &context);
			while (ptr != NULL)
			{
				// Copies the messages to heap memory and saves them to a queue
				queue.push(new String(ptr));
				ptr = strtok_s(NULL, separator, &context);
			}

		} while (length > 0 && running);

		// Once the connection is closed cleans up all of its resources
		{
			SOCKET socket = client;
			client = NULL;
			closesocket(socket);
			WSACleanup();
		}
	}

	return 0;
}

// Called by the Lua script when a TeamSpeak command is used
// Sends a message using the ClientQuery socket

int SendCommand(lua_State *L)
{
	// Stops if the socket is not connected or no message has been sent
	if (client == NULL || lua_type(L, 1) == -1) return 0;

	// Reads the message and sends it
	const char *buffer = lua_tostring(L, 1);
	send(client, buffer, strlen(buffer), 0);
	send(client, "\n", 1, 0);
	return 0;
}

// Called by the Lua script when a new message is received
// Saves a message to chat history

int SaveChatMessage(lua_State *L)
{
	// Stops if chat history is disabled or being loaded
	if (loading_history || max_history < 1) return 0;

	// Creates a new message
	ChatMessage *message = new ChatMessage();
	message->sender = String(lua_tostring(L, 1));
	message->message = String(lua_tostring(L, 2));
	// Saves the Color userdata directly
	message->color = *(Color *)lua_touserdata(L, 3);
	message->icon = String(lua_tostring(L, 4));

	// Inserts the message at the end of the chat history
	history.push_back(message);
	// Removes the first few messages if the limit has been reached
	while (history.size() > max_history)
	{
		delete history.front();
		history.pop_front();
	}

	return 0;
}

// Called by the Lua script once the chat GUI loads
// Loads all messages from chat histor into the game

int LoadChatMessages(lua_State *L)
{
	// Stops if there is no chat history
	if (max_history < 1 || history.empty()) return 0;
	loading_history = true;

	// Indexes the global TeamSpeak variable
	ChatMessage *message;
	lua_getglobal(L, "TeamSpeak");
	int index = lua_gettop(L);

	// And loads each message inside the chat history
	for (auto i = history.begin(); i != history.end(); i++)
	{
		message = *i;
		lua_getfield(L, index, "ShowMessage");
		lua_pushlstring(L, message->sender.value(), message->sender.length());
		lua_pushlstring(L, message->message.value(), message->message.length());
		// Recreates and pushes the userdata
		message->color.push(L);
		// Sets an icon if required
		if (message->icon.value() == NULL) lua_pushnil(L);
		else lua_pushlstring(L, message->icon.value(), message->icon.length());
		lua_pcall(L, 4, 0, 0);
	}

	loading_history = false;
	return 0;
}

// Requires the TeamSpeak Lua script and loads it into the game

void WINAPI OnRequire(lua_State *L, LPCSTR file, LPVOID param)
{
	// If the required file matches any we need to override
	if (strcmp(file, "lib/managers/chatmanager") == 0
	 || strcmp(file, "lib/managers/hud/hudchat") == 0
	 || strcmp(file, "lib/utils/game_state_machine/gamestatemachine") == 0)
	{
		// Checks if the global TeamSpeak variable has been defined
		lua_getglobal(L, "TeamSpeak");
		int type = lua_type(L, -1);

		// Load that file into the game
		if (luaL_loadfile(L, "TeamSpeak/TeamSpeak.lua") == 0)
		{
			// And execute it
			lua_pcall(L, 0, LUA_MULTRET, 0);

			// Make sure to only initalize once for each states
			if (type != 0) return;

			// Indexes the global TeamSpeak variable
			lua_getglobal(L, "TeamSpeak");
			int index = lua_gettop(L);

			// Check the chat history option
			lua_getfield(L, index, "Options");
			lua_getfield(L, -1, "ChatHistory");
			max_history = (unsigned int)lua_tonumber(L, -1);

			// Maps C++ functions to Lua variables inside the TeamSpeak object
			lua_pushcfunction(L, &SendCommand);
			lua_setfield(L, index, "Send");
			lua_pushcfunction(L, &SaveChatMessage);
			lua_setfield(L, index, "SaveChatMessage");
			lua_pushcfunction(L, &LoadChatMessages);
			lua_setfield(L, index, "LoadChatMessages");

			// Register a Lua hook if chat history is enabled
			if (max_history > 0)
			{
				lua_getfield(L, index, "Hooks");
				lua_getfield(L, -1, "Add");
				lua_pushvalue(L, -2);
				lua_pushstring(L, "ChatManagerOnLoad");
				lua_pushcfunction(L, LoadChatMessages);
				lua_pcall(L, 3, 0, 0);
			}

			// Note that the Lua side of this mod still requires initialization
			initialized = FALSE;

			// Saves the current Lua state and creates the network thread
			state = L;
			if (!running) CreateThread(NULL, 0, Main, NULL, 0, NULL);
		}
	}
}

// Runs on game ticks and sends messages from TeamSpeak to the Lua script

void WINAPI OnGameTick(lua_State *L, LPCSTR type, LPVOID param)
{
	// If the Lua state matches out initial script
	// load state and the tick type is an update tick
	if (L == state && strcmp(type, "update") == 0)
	{
		// Index the global TeamSpeak variable
		lua_getglobal(L, "TeamSpeak");
		int index = lua_gettop(L);

		// Initialize the Lua part of the mod if a connection
		// to ClientQuery has been established
		if (!initialized && client != NULL)
		{
			initialized = TRUE;
			// Updates the list of clients connected to the server
			lua_getfield(L, index, "FetchInfo");
			lua_pcall(L, 0, 0, 0);
		}

		// Pass any recived messages from TeamSpeak to a Lua function
		if (!queue.empty())
		{
			for (String *message; queue.try_pop(message);)
			{
				lua_getfield(L, index, "OnReceive");
				lua_pushlstring(L, message->value(), message->length());
				lua_pcall(L, 1, 0, 0);
				delete message;
			}
		}
	}
}

// DLL entry point

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		// Registers a callback for when the game requires an internal file
		RegisterCallback(REQUIRE_CALLBACK, &OnRequire, NULL);
		// Registers a callback for game ticks
		RegisterCallback(GAMETICK_CALLBACK, &OnGameTick, NULL);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		// Stops the network loop
		running = FALSE;
		break;
	}
	return TRUE;
}
<commit_msg>add missing memory deallocation<commit_after>#define WIN32_LEAN_AND_MEAN

#include <SDKDDKVer.h>
#include <windows.h>
#include "HookAPI.h"
#include "TeamSpeak.h"
#include <ws2tcpip.h>
#include <atomic>
#include <list>
#include <concurrent_queue.h>

#pragma comment (lib, "Ws2_32.lib")

// Default buffer length
#define BUFLEN 4096

// Socket used for TeamSpeak communication
std::atomic<SOCKET> client = NULL;
// Lua state used when requiring script files
std::atomic<lua_State *> state = NULL;
// Boolean telling the socket thread whether to keep the network loop running
std::atomic<bool> running = FALSE;
// Boolean telling if the TeamSpeak mod has been initialized
std::atomic<bool> initialized = TRUE;
// Queue of commands to be sent to the Lua script
Concurrency::concurrent_queue<String *> queue;
// Chat message history and its length and status
std::list<ChatMessage *> history;
unsigned int max_history = 20;
bool loading_history = false;

// Tries to connect to TeamSpeak using ClientQuery
// Returns a new socket or NULL on failure

SOCKET Connect(PCSTR hostname, PCSTR port)
{
	// Creates a structure used for containing the socket information
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) return NULL;

	// Creates a structure used for containing the connection information
	struct addrinfo *info, *ptr, hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	result = getaddrinfo(hostname, port, &hints, &info);
	if (result != 0)
	{
		WSACleanup();
		return NULL;
	}

	// Tries to connect to the specified address
	SOCKET client = INVALID_SOCKET;
	for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
	{
		client = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (client == INVALID_SOCKET)
		{
			WSACleanup();
			return NULL;
		}
		result = connect(client, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (result == SOCKET_ERROR)
		{
			closesocket(client);
			client = INVALID_SOCKET;
			continue;
		}
		break;
	}

	// Releases the address information strcuture from memory
	freeaddrinfo(info);

	// Return NULL if the connection could not be established
	if (client == INVALID_SOCKET)
	{
		WSACleanup();
		return NULL;
	}

	// Sets keep alive to true for the socket
	char value = 1;
	setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));

	return client;
}

// Socket thread
// Executes a loop reading messages and passing them to the Lua script

DWORD WINAPI Main(LPVOID param)
{
	int length;
	char buffer[BUFLEN];
	char *ptr, *context;
	const char *separator = "\n\r";
	const char *command = "clientnotifyregister schandlerid=0 event=any\n";

	// Starts the network loop
	for (running = true; running;)
	{
		// Connects to the local TeamSpeak ClientQuery and retries on failure
		client = Connect("127.0.0.1", "25639");
		if (client == NULL) continue;

		// Receives the initial ClientQuery headers
		for (int header = 182; header > 0; header -= length)
			length = recv(client, buffer, BUFLEN, 0);

		// Sends a "listen to all events" command and receives its response
		send(client, command, strlen(command), 0);
		recv(client, buffer, BUFLEN, 0);

		// Reads messages from the ClientQuery input stream
		do
		{
			// Receives a message and null terminates it
			buffer[length = recv(client, buffer, BUFLEN, 0)] = 0;
			// Splits up different messages that might be in the same buffer
			ptr = strtok_s(buffer, separator, &context);
			while (ptr != NULL)
			{
				// Copies the messages to heap memory and saves them to a queue
				queue.push(new String(ptr));
				ptr = strtok_s(NULL, separator, &context);
			}

		} while (length > 0 && running);

		// Once the connection is closed cleans up all of its resources
		{
			SOCKET socket = client;
			client = NULL;
			closesocket(socket);
			WSACleanup();
		}
	}

	return 0;
}

// Called by the Lua script when a TeamSpeak command is used
// Sends a message using the ClientQuery socket

int SendCommand(lua_State *L)
{
	// Stops if the socket is not connected or no message has been sent
	if (client == NULL || lua_type(L, 1) == -1) return 0;

	// Reads the message and sends it
	const char *buffer = lua_tostring(L, 1);
	send(client, buffer, strlen(buffer), 0);
	send(client, "\n", 1, 0);
	return 0;
}

// Called by the Lua script when a new message is received
// Saves a message to chat history

int SaveChatMessage(lua_State *L)
{
	// Stops if chat history is disabled or being loaded
	if (loading_history || max_history < 1) return 0;

	// Creates a new message
	ChatMessage *message = new ChatMessage();
	message->sender = String(lua_tostring(L, 1));
	message->message = String(lua_tostring(L, 2));
	// Saves the Color userdata directly
	message->color = *(Color *)lua_touserdata(L, 3);
	message->icon = String(lua_tostring(L, 4));

	// Inserts the message at the end of the chat history
	history.push_back(message);
	// Removes the first few messages if the limit has been reached
	while (history.size() > max_history)
	{
		delete history.front();
		history.pop_front();
	}

	return 0;
}

// Called by the Lua script once the chat GUI loads
// Loads all messages from chat histor into the game

int LoadChatMessages(lua_State *L)
{
	// Stops if there is no chat history
	if (max_history < 1 || history.empty()) return 0;
	loading_history = true;

	// Indexes the global TeamSpeak variable
	ChatMessage *message;
	lua_getglobal(L, "TeamSpeak");
	int index = lua_gettop(L);

	// And loads each message inside the chat history
	for (auto i = history.begin(); i != history.end(); i++)
	{
		message = *i;
		lua_getfield(L, index, "ShowMessage");
		lua_pushlstring(L, message->sender.value(), message->sender.length());
		lua_pushlstring(L, message->message.value(), message->message.length());
		// Recreates and pushes the userdata
		message->color.push(L);
		// Sets an icon if required
		if (message->icon.value() == NULL) lua_pushnil(L);
		else lua_pushlstring(L, message->icon.value(), message->icon.length());
		lua_pcall(L, 4, 0, 0);
	}

	loading_history = false;
	return 0;
}

// Requires the TeamSpeak Lua script and loads it into the game

void WINAPI OnRequire(lua_State *L, LPCSTR file, LPVOID param)
{
	// If the required file matches any we need to override
	if (strcmp(file, "lib/managers/chatmanager") == 0
	 || strcmp(file, "lib/managers/hud/hudchat") == 0
	 || strcmp(file, "lib/utils/game_state_machine/gamestatemachine") == 0)
	{
		// Checks if the global TeamSpeak variable has been defined
		lua_getglobal(L, "TeamSpeak");
		int type = lua_type(L, -1);

		// Load that file into the game
		if (luaL_loadfile(L, "TeamSpeak/TeamSpeak.lua") == 0)
		{
			// And execute it
			lua_pcall(L, 0, LUA_MULTRET, 0);

			// Make sure to only initalize once for each states
			if (type != 0) return;

			// Indexes the global TeamSpeak variable
			lua_getglobal(L, "TeamSpeak");
			int index = lua_gettop(L);

			// Check the chat history option
			lua_getfield(L, index, "Options");
			lua_getfield(L, -1, "ChatHistory");
			max_history = (unsigned int)lua_tonumber(L, -1);

			// Maps C++ functions to Lua variables inside the TeamSpeak object
			lua_pushcfunction(L, &SendCommand);
			lua_setfield(L, index, "Send");
			lua_pushcfunction(L, &SaveChatMessage);
			lua_setfield(L, index, "SaveChatMessage");
			lua_pushcfunction(L, &LoadChatMessages);
			lua_setfield(L, index, "LoadChatMessages");

			// Register a Lua hook if chat history is enabled
			if (max_history > 0)
			{
				lua_getfield(L, index, "Hooks");
				lua_getfield(L, -1, "Add");
				lua_pushvalue(L, -2);
				lua_pushstring(L, "ChatManagerOnLoad");
				lua_pushcfunction(L, LoadChatMessages);
				lua_pcall(L, 3, 0, 0);
			}

			// Note that the Lua side of this mod still requires initialization
			initialized = FALSE;

			// Saves the current Lua state and creates the network thread
			state = L;
			if (!running) CreateThread(NULL, 0, Main, NULL, 0, NULL);
		}
	}
}

// Runs on game ticks and sends messages from TeamSpeak to the Lua script

void WINAPI OnGameTick(lua_State *L, LPCSTR type, LPVOID param)
{
	// If the Lua state matches out initial script
	// load state and the tick type is an update tick
	if (L == state && strcmp(type, "update") == 0)
	{
		// Index the global TeamSpeak variable
		lua_getglobal(L, "TeamSpeak");
		int index = lua_gettop(L);

		// Initialize the Lua part of the mod if a connection
		// to ClientQuery has been established
		if (!initialized && client != NULL)
		{
			initialized = TRUE;
			// Updates the list of clients connected to the server
			lua_getfield(L, index, "FetchInfo");
			lua_pcall(L, 0, 0, 0);
		}

		// Pass any recived messages from TeamSpeak to a Lua function
		if (!queue.empty())
		{
			for (String *message; queue.try_pop(message);)
			{
				lua_getfield(L, index, "OnReceive");
				lua_pushlstring(L, message->value(), message->length());
				lua_pcall(L, 1, 0, 0);
				delete message;
			}
		}
	}
}

// DLL entry point

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		// Registers a callback for when the game requires an internal file
		RegisterCallback(REQUIRE_CALLBACK, &OnRequire, NULL);
		// Registers a callback for game ticks
		RegisterCallback(GAMETICK_CALLBACK, &OnGameTick, NULL);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		// Stops the network loop
		running = FALSE;
		// Free memory
		for (String *message; !queue.empty();) if (queue.try_pop(message)) delete message;
		for (; !history.empty(); history.pop_front()) delete history.front();
		break;
	}
	return TRUE;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
	if(argc==1)			//quit if no argument
	{
		cerr<<"Usage: "<<argv[0]<<" filename[s]\n";
		exit(EXIT_FAILURE);
	}

	int i;
	vector<int> vi;

	for(int file=1;file<argc;file++)
	{
		ifstream fin;		//open stream
		fin.open(argv[file]);

		while(fin>>i)
			vi.push_back(i);

		fin.clear();
		fin.close();
	}

	for(decltype(vi.size()) begin=0,end=vi.size()-1;
		begin>end ; begin++,end--)
		cout<<vi[begin]+vi[end]<<" ";

	return 0;
}<commit_msg>修改3_20.cpp<commit_after>#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
	if(argc==1)			//quit if no argument
	{
		cerr<<"Usage: "<<argv[0]<<" filename[s]\n";
		exit(EXIT_FAILURE);
	}

	int i;
	vector<int> vi;

	for(int file=1;file<argc;file++)
	{
		ifstream fin;		//open stream
		fin.open(argv[file]);

		while(fin>>i)
			vi.push_back(i);

		fin.clear();
		fin.close();
	}

	for(decltype(vi.size()) begin=0,end=vi.size()-1;
		begin<=end ; begin++,end--)
		cout<<vi[begin]+vi[end]<<" ";

	return 0;
}<|endoftext|>