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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date: 2007-04-17 11:54:52 +0200 (Tue, 17 Apr 2007) $
Version:   $Revision: 10161 $

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 "QmitkRegionGrowingControls.h"
#include "QmitkRegionGrowing.h"
#include "QmitkStdMultiWidget.h"
#include "QmitkTreeNodeSelector.h"

#include <qaction.h>
#include <qmessagebox.h>

#include "mitkColorProperty.h"
#include "mitkDataStorage.h"
#include "mitkDataTreeHelper.h"
#include "mitkGlobalInteraction.h"
#include "mitkImageAccessByItk.h"
#include "mitkITKImageImport.h"
#include "mitkPointSetInteractor.h"
#include "mitkProperties.h"

#include <itkConnectedThresholdImageFilter.h>

#include <limits>

#include "icon.xpm"

QmitkRegionGrowing::QmitkRegionGrowing(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
: QmitkFunctionality(parent, name, it),
  m_MultiWidget(mitkStdMultiWidget),
  m_Controls(NULL)
{
  SetAvailability(true);
}

QmitkRegionGrowing::~QmitkRegionGrowing()
{
}

QWidget * QmitkRegionGrowing::CreateMainWidget(QWidget *parent)
{
  if ( m_MultiWidget == NULL )
  {
    m_MultiWidget = new QmitkStdMultiWidget( parent );
  }
  return m_MultiWidget;
}

QWidget * QmitkRegionGrowing::CreateControlWidget(QWidget *parent)
{
  if (m_Controls == NULL)
  {
    m_Controls = new QmitkRegionGrowingControls(parent);
  }
  return m_Controls;
}

void QmitkRegionGrowing::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->btnRegionGrow), SIGNAL(clicked()),
                                              this, SLOT(DoRegionGrowing()) );
  }
}

QAction * QmitkRegionGrowing::CreateAction(QActionGroup *parent)
{
  QAction* action;
  action = new QAction( tr( "Quite simple region grower" ), QPixmap((const char**)icon_xpm), tr( "You will never see this" ), 0, parent, "QmitkRegionGrowing" );
  return action;
}

void QmitkRegionGrowing::TreeChanged()
{
  m_Controls->m_TreeNodeSelector->SetDataTreeNodeIterator( GetDataTreeIterator() );
}

void QmitkRegionGrowing::Activated()
{
  QmitkFunctionality::Activated();

  if (m_PointSetNode.IsNull()) // only once create a new DataTreeNode containing a PointSet with some interaction
  {
    // new node and data item
    m_PointSetNode = mitk::DataTreeNode::New();
    m_PointSet = mitk::PointSet::New();
    m_PointSetNode->SetData( m_PointSet );

    // new behaviour/interaction for the pointset node
    mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New("pointsetinteractor", m_PointSetNode);
    mitk::GlobalInteraction::GetInstance()->AddInteractor( interactor );

    // add the pointset to the data tree (for rendering)
    GetDataTreeIterator()->Add( m_PointSetNode );
  }
}

void QmitkRegionGrowing::DoRegionGrowing()
{
  const mitk::DataTreeIteratorClone* iterator = m_Controls->m_TreeNodeSelector->GetSelectedIterator(); // should never fail, the selection widget cares for that
  if (!iterator)
  {
    // Nothing selected. Inform the user and return
    QMessageBox::information( NULL, "Region growing functionality", "Please load and select an image before region growing.");
    return;
  }

  mitk::DataTreeNode* node = (*iterator)->Get();
  if ( node )
  {
    // here we have a valid mitk::DataTreeNode

    // a node itself is not very useful, we need its data item (the image)
    mitk::BaseData* data = node->GetData();
    if (data)
    {
      // test if this data item is an image or not (could also be a surface or something totally different)
      mitk::Image* image = dynamic_cast<mitk::Image*>( data );
      if (image)
      {
        std::string name;
        std::cout << "Performing region growing for image";
        if (node->GetName(name))
        {
          // a property called "name" was found for this DataTreeNode
          std::cout << "'" << name << "'";
        }
        std::cout << "." << std::endl;

        // So we have an image. Let's see if the user has set some seed points already
        if ( m_PointSet->GetSize() == 0 )
        {
          // no points there. Not good for region growing
          QMessageBox::information( NULL, "Region growing functionality", "Please set some seed points inside the image first.\n(hold Shift key and click left mouse button inside the image.)");
          return;
        }

        // actually perform region growing. Here we have both an image and some seed points
        AccessByItk_1( image, ItkImageProcessing, image->GetGeometry() ); // some magic to call the correctly templated function

      }
    }
  }

}

template < typename TPixel, unsigned int VImageDimension >
void QmitkRegionGrowing::ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry )
{
  typedef itk::Image< TPixel, VImageDimension > InputImageType;
  typedef typename InputImageType::IndexType    IndexType;

  // instantiate an ITK region growing filter, set its parameters
  typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
  typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
  regionGrower->SetInput( itkImage ); // don't forget this

  // determine a thresholding interval
  IndexType seedIndex;
  TPixel min( std::numeric_limits<TPixel>::max() );
  TPixel max( std::numeric_limits<TPixel>::min() );
  for ( mitk::PointSet::PointsConstIterator pointsIterator = m_PointSet->GetPointSet()->GetPoints()->Begin(); // really nice syntax to get an interator for all points
        pointsIterator != m_PointSet->GetPointSet()->GetPoints()->End();
        ++pointsIterator )
  {
    // first test if this point is inside the image at all
    if ( !imageGeometry->IsInside( pointsIterator.Value()) )
      continue;

    // convert world coordinates to image indices
    imageGeometry->WorldToIndex( pointsIterator.Value(), seedIndex);

    // get the pixel value at this point
    TPixel currentPixelValue = itkImage->GetPixel( seedIndex );

    // adjust minimum and maximum values
    if (currentPixelValue > max)
      max = currentPixelValue;

    if (currentPixelValue < min)
      min = currentPixelValue;

    regionGrower->AddSeed( seedIndex );
  }

  std::cout << "Values between " << min << " and " << max << std::endl;

  min -= 30;
  max += 30;

  // set thresholds and execute filter
  regionGrower->SetLower( min );
  regionGrower->SetUpper( max );

  regionGrower->Update();

  mitk::Image::Pointer resultImage = mitk::ImportItkImage( regionGrower->GetOutput() );
  mitk::DataTreeNode::Pointer newNode = mitk::DataTreeNode::New();
  newNode->SetData( resultImage );

  // set some properties
  mitk::DataTreeNodeFactory::SetDefaultImageProperties( newNode );
  newNode->SetProperty("binary", new mitk::BoolProperty(true));
  newNode->SetProperty("name", new mitk::StringProperty("dumb segmentation"));
  newNode->SetProperty("color", new mitk::ColorProperty(1.0,0.0,0.0));
  //newNode->SetProperty("volumerendering", new mitk::BoolProperty(true));
  newNode->SetProperty("layer", new mitk::IntProperty(1));
  newNode->SetProperty("opacity", new mitk::FloatProperty(0.5));

  // add result to data tree
  mitk::DataStorage::GetInstance()->Add( newNode );
}

<commit_msg>CHG: set name of point set DataTreeNode<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date: 2007-04-17 11:54:52 +0200 (Tue, 17 Apr 2007) $
Version:   $Revision: 10161 $

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 "QmitkRegionGrowingControls.h"
#include "QmitkRegionGrowing.h"
#include "QmitkStdMultiWidget.h"
#include "QmitkTreeNodeSelector.h"

#include <qaction.h>
#include <qmessagebox.h>

#include "mitkColorProperty.h"
#include "mitkDataStorage.h"
#include "mitkDataTreeHelper.h"
#include "mitkGlobalInteraction.h"
#include "mitkImageAccessByItk.h"
#include "mitkITKImageImport.h"
#include "mitkPointSetInteractor.h"
#include "mitkProperties.h"

#include <itkConnectedThresholdImageFilter.h>

#include <limits>

#include "icon.xpm"

QmitkRegionGrowing::QmitkRegionGrowing(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
: QmitkFunctionality(parent, name, it),
  m_MultiWidget(mitkStdMultiWidget),
  m_Controls(NULL)
{
  SetAvailability(true);
}

QmitkRegionGrowing::~QmitkRegionGrowing()
{
}

QWidget * QmitkRegionGrowing::CreateMainWidget(QWidget *parent)
{
  if ( m_MultiWidget == NULL )
  {
    m_MultiWidget = new QmitkStdMultiWidget( parent );
  }
  return m_MultiWidget;
}

QWidget * QmitkRegionGrowing::CreateControlWidget(QWidget *parent)
{
  if (m_Controls == NULL)
  {
    m_Controls = new QmitkRegionGrowingControls(parent);
  }
  return m_Controls;
}

void QmitkRegionGrowing::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->btnRegionGrow), SIGNAL(clicked()),
                                              this, SLOT(DoRegionGrowing()) );
  }
}

QAction * QmitkRegionGrowing::CreateAction(QActionGroup *parent)
{
  QAction* action;
  action = new QAction( tr( "Quite simple region grower" ), QPixmap((const char**)icon_xpm), tr( "You will never see this" ), 0, parent, "QmitkRegionGrowing" );
  return action;
}

void QmitkRegionGrowing::TreeChanged()
{
  m_Controls->m_TreeNodeSelector->SetDataTreeNodeIterator( GetDataTreeIterator() );
}

void QmitkRegionGrowing::Activated()
{
  QmitkFunctionality::Activated();

  if (m_PointSetNode.IsNull()) // only once create a new DataTreeNode containing a PointSet with some interaction
  {
    // new node and data item
    m_PointSetNode = mitk::DataTreeNode::New();
	m_PointSetNode->GetPropertyList()->SetProperty("name", new mitk::StringProperty("Seedpoints for region growing"));
	m_PointSet = mitk::PointSet::New();
    m_PointSetNode->SetData( m_PointSet );

    // new behaviour/interaction for the pointset node
    mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New("pointsetinteractor", m_PointSetNode);
    mitk::GlobalInteraction::GetInstance()->AddInteractor( interactor );

    // add the pointset to the data tree (for rendering)
    GetDataTreeIterator()->Add( m_PointSetNode );
  }
}

void QmitkRegionGrowing::DoRegionGrowing()
{
  const mitk::DataTreeIteratorClone* iterator = m_Controls->m_TreeNodeSelector->GetSelectedIterator(); // should never fail, the selection widget cares for that
  if (!iterator)
  {
    // Nothing selected. Inform the user and return
    QMessageBox::information( NULL, "Region growing functionality", "Please load and select an image before region growing.");
    return;
  }

  mitk::DataTreeNode* node = (*iterator)->Get();
  if ( node )
  {
    // here we have a valid mitk::DataTreeNode

    // a node itself is not very useful, we need its data item (the image)
    mitk::BaseData* data = node->GetData();
    if (data)
    {
      // test if this data item is an image or not (could also be a surface or something totally different)
      mitk::Image* image = dynamic_cast<mitk::Image*>( data );
      if (image)
      {
        std::string name;
        std::cout << "Performing region growing for image";
        if (node->GetName(name))
        {
          // a property called "name" was found for this DataTreeNode
          std::cout << "'" << name << "'";
        }
        std::cout << "." << std::endl;

        // So we have an image. Let's see if the user has set some seed points already
        if ( m_PointSet->GetSize() == 0 )
        {
          // no points there. Not good for region growing
          QMessageBox::information( NULL, "Region growing functionality", "Please set some seed points inside the image first.\n(hold Shift key and click left mouse button inside the image.)");
          return;
        }

        // actually perform region growing. Here we have both an image and some seed points
        AccessByItk_1( image, ItkImageProcessing, image->GetGeometry() ); // some magic to call the correctly templated function

      }
    }
  }

}

template < typename TPixel, unsigned int VImageDimension >
void QmitkRegionGrowing::ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry )
{
  typedef itk::Image< TPixel, VImageDimension > InputImageType;
  typedef typename InputImageType::IndexType    IndexType;

  // instantiate an ITK region growing filter, set its parameters
  typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
  typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
  regionGrower->SetInput( itkImage ); // don't forget this

  // determine a thresholding interval
  IndexType seedIndex;
  TPixel min( std::numeric_limits<TPixel>::max() );
  TPixel max( std::numeric_limits<TPixel>::min() );
  for ( mitk::PointSet::PointsConstIterator pointsIterator = m_PointSet->GetPointSet()->GetPoints()->Begin(); // really nice syntax to get an interator for all points
        pointsIterator != m_PointSet->GetPointSet()->GetPoints()->End();
        ++pointsIterator )
  {
    // first test if this point is inside the image at all
    if ( !imageGeometry->IsInside( pointsIterator.Value()) )
      continue;

    // convert world coordinates to image indices
    imageGeometry->WorldToIndex( pointsIterator.Value(), seedIndex);

    // get the pixel value at this point
    TPixel currentPixelValue = itkImage->GetPixel( seedIndex );

    // adjust minimum and maximum values
    if (currentPixelValue > max)
      max = currentPixelValue;

    if (currentPixelValue < min)
      min = currentPixelValue;

    regionGrower->AddSeed( seedIndex );
  }

  std::cout << "Values between " << min << " and " << max << std::endl;

  min -= 30;
  max += 30;

  // set thresholds and execute filter
  regionGrower->SetLower( min );
  regionGrower->SetUpper( max );

  regionGrower->Update();

  mitk::Image::Pointer resultImage = mitk::ImportItkImage( regionGrower->GetOutput() );
  mitk::DataTreeNode::Pointer newNode = mitk::DataTreeNode::New();
  newNode->SetData( resultImage );

  // set some properties
  mitk::DataTreeNodeFactory::SetDefaultImageProperties( newNode );
  newNode->SetProperty("binary", new mitk::BoolProperty(true));
  newNode->SetProperty("name", new mitk::StringProperty("dumb segmentation"));
  newNode->SetProperty("color", new mitk::ColorProperty(1.0,0.0,0.0));
  //newNode->SetProperty("volumerendering", new mitk::BoolProperty(true));
  newNode->SetProperty("layer", new mitk::IntProperty(1));
  newNode->SetProperty("opacity", new mitk::FloatProperty(0.5));

  // add result to data tree
  mitk::DataStorage::GetInstance()->Add( newNode );
}

<|endoftext|>


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt 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.

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

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkExceptionObject.h"
#include "otbImage.h"
#include <iostream>

#include "otbSVMModel.h"

namespace otb
{

class LinearKernelFunctor : public GenericKernelFunctorBase
{
public:
  LinearKernelFunctor() : GenericKernelFunctorBase() {}
  virtual ~LinearKernelFunctor() {}

  virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const
  {
    return this->dot(x, y);
  }
};

}

int otbSVMModelGenericKernelLoadSave(int argc, char* argv[])
{
  typedef unsigned char InputPixelType;
  typedef unsigned char LabelPixelType;
  const unsigned int Dimension = 2;

  typedef otb::Image<InputPixelType,  Dimension> InputImageType;

  typedef otb::SVMModel<InputPixelType, LabelPixelType> ModelType;

  ModelType::Pointer svmModel = ModelType::New();

  otb::LinearKernelFunctor lFunctor;

  svmModel->SetKernelFunctor(&lFunctor);

  svmModel->LoadModel(argv[1]);
  svmModel->SaveModel(argv[2]);

  return EXIT_SUCCESS;
}
<commit_msg>ENH: implement Clone method<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt 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.

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

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkExceptionObject.h"
#include "otbImage.h"
#include <iostream>

#include "otbSVMModel.h"

namespace otb
{

class LinearKernelFunctor : public GenericKernelFunctorBase
{
public:
  typedef LinearKernelFunctor                 Self;
  typedef GenericKernelFunctorBase            Superclass;

  LinearKernelFunctor() : GenericKernelFunctorBase() {}
  virtual ~LinearKernelFunctor() {}

  // Deep copy operator
  virtual GenericKernelFunctorBase* Clone() const
  {
    return new Self(*this);
  }

  virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter&) const
  {
    return this->dot(x, y);
  }

protected:
  LinearKernelFunctor(const Self& copy)
  : Superclass(copy)
  {
    *this = copy;
  }

  LinearKernelFunctor& operator=(const Self& copy)
  {
    Superclass::operator =(copy);
    return *this;
  }
};

}

int otbSVMModelGenericKernelLoadSave(int argc, char* argv[])
{
  typedef unsigned char InputPixelType;
  typedef unsigned char LabelPixelType;
  const unsigned int Dimension = 2;

  typedef otb::Image<InputPixelType,  Dimension> InputImageType;

  typedef otb::SVMModel<InputPixelType, LabelPixelType> ModelType;

  ModelType::Pointer svmModel = ModelType::New();

  otb::LinearKernelFunctor lFunctor;

  svmModel->SetKernelFunctor(&lFunctor);

  svmModel->LoadModel(argv[1]);
  svmModel->SaveModel(argv[2]);

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "EditorInputHandler.h"

EditorInputHandler::EditorInputHandler(
	HINSTANCE handleInstance,
	HWND handle,
	Camera* camera,
	int w,
	int h)
{
	this->m_Width = w;
	this->m_Height = h;
	HRESULT hr = DirectInput8Create(
		handleInstance,
		DIRECTINPUT_VERSION,
		IID_IDirectInput8,
		(void**)&m_directInput,
		NULL);

	//hr = m_directInput->CreateDevice(GUID_SysKeyboard,
	//	&DIKeyboard,
	//	NULL);

	hr = m_directInput->CreateDevice(GUID_SysMouse,
		&DIMouse,
		NULL);

	//hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
	//hr = DIKeyboard->SetCooperativeLevel(handle, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

	hr = DIMouse->SetDataFormat(&c_dfDIMouse);
	hr = DIMouse->SetCooperativeLevel(handle, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND);
	//this->m_hwnd	    = handle;
	this->m_Camera	    = camera;

	this->m_PreviousPos = camera->GetCameraPos();
	for (size_t i = 0; i < NUMBOOLS; i++)
	{
		this->m_KeysHeld[i] = false;
	}
	DIMouse->Acquire();

}

EditorInputHandler::~EditorInputHandler()
{
}

void EditorInputHandler::KeyboardMovement(double dT)
{
	float speed = 4.0f * dT;
	float translateCameraX = 0, translateCameraY = 0, translateCameraZ = 0;
	if (m_KeysHeld[Bools::SHIFT] == true)
	{
		if (this->m_KeysHeld[Bools::W] == true)
			translateCameraZ += speed;

		if (this->m_KeysHeld[Bools::A] == true)
			translateCameraX -= speed;
		if (this->m_KeysHeld[Bools::S] == true)
			translateCameraZ -= speed;
		if (this->m_KeysHeld[Bools::D] == true)
			translateCameraX += speed;
		if (this->m_KeysHeld[Bools::C] == true)
			translateCameraY -= speed;
		if (this->m_KeysHeld[Bools::SPACE] == true)
			translateCameraY -= speed;

			MouseZoom(dT);
	}
	else {
	if (this->m_KeysHeld[Bools::SPACE] == true)
		translateCameraY += speed;
	}
	if (this->m_KeysHeld[ALT] == true)
		MouseMovement(dT);

	if ((translateCameraY || translateCameraZ || translateCameraX))
	{
		DirectX::XMFLOAT3 posTranslation =
			DirectX::XMFLOAT3(
				float(translateCameraX),
				float(translateCameraY),
				float(translateCameraZ)
			);

		this->m_PreviousPos = this->m_Camera->GetCameraPos();
		this->m_Camera->ApplyLocalTranslation(
			float(translateCameraX),
			float(translateCameraY),
			float(translateCameraZ)
		);
		this->m_Camera->UpdateView();
	}
}

void EditorInputHandler::MouseMovement(double dT)
{
	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);
	float pitch = 0;
	float yaw = 0;
	float rotationAmount = (DirectX::XM_PI / 8) / 2;

		if (m_mouse.currentState.rgbButtons[0])
		{
			if ((m_mouse.currentState.lX != m_mouse.lastState.lX) || (m_mouse.currentState.lY != m_mouse.lastState.lY))
			{
				pitch += m_mouse.currentState.lX * 0.01f;

				yaw += m_mouse.currentState.lY * 0.01f;

				// Ensure the mouse location doesn't exceed the screen width or height.
				if (this->m_mouse.x < 0) { this->m_mouse.x = 0; }
				if (this->m_mouse.y < 0) { this->m_mouse.y = 0; }

				if (this->m_mouse.x > m_Width) { this->m_mouse.x = m_Width; }
				if (this->m_mouse.y > m_Height) { this->m_mouse.y = m_Height; }

				m_mouse.lastState = m_mouse.currentState;
			}
		}

	DirectX::XMFLOAT4 camUpFloat;
	DirectX::XMFLOAT3 camPosFloat;
	DirectX::XMFLOAT3 camTargetFloat;
	this->m_Camera->GetCameraUp(camUpFloat);
	camPosFloat = this->m_Camera->GetCameraPos();
	camTargetFloat = this->m_Camera->GetLookAt();

	DirectX::XMVECTOR rotationVector;

	DirectX::XMVECTOR camUpVec = { 0.0f, 1.0f,0.0f,0.0f };//DirectX::XMLoadFloat4(&camUpFloat);
	DirectX::XMVECTOR camPosVec = DirectX::XMLoadFloat3(&camPosFloat);
	DirectX::XMVECTOR camTargetVec = DirectX::XMLoadFloat3(&camTargetFloat);

	DirectX::XMVECTOR camDir = DirectX::XMVector3Normalize(DirectX::XMVectorSubtract(camTargetVec, camPosVec));

	DirectX::XMVECTOR camRight = DirectX::XMVector3Normalize(DirectX::XMVector3Cross(camDir, camUpVec));

	camRight.m128_f32[3] = rotationAmount * -yaw;
	camUpVec.m128_f32[3] = rotationAmount * pitch;

	if (pitch||yaw)
	{
		this->m_Camera->RotateCamera(camRight);
		this->m_Camera->RotateCamera(camUpVec);
	};

	this->m_Camera->UpdateView();
}

void EditorInputHandler::MouseZoom(double dT)
{

	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);

	float speedrot = 2.5f * dT;
	float translateCameraZ = 0;

	if (m_mouse.currentState.rgbButtons[0])
	{
		if (m_mouse.currentState.lY < 0)
		{
			translateCameraZ += speedrot;
		}
		if (m_mouse.currentState.lY > 0)
		{
			translateCameraZ -= speedrot;
		}

	}
	if (translateCameraZ)
	{
		DirectX::XMFLOAT3 posTranslation =
			DirectX::XMFLOAT3(
				0.0f,
				0.0f,
				float(translateCameraZ)
			);

		this->m_PreviousPos = this->m_Camera->GetCameraPos();
		this->m_Camera->ApplyLocalTranslation(
			0.0f,
			0.0f,
			float(translateCameraZ)
		);
		this->m_Camera->UpdateView();
	}
}

void EditorInputHandler::CameraReset()
{
		this->m_Camera->Initialize(this->m_Width / this->m_Height);
		this->m_Camera->SetLookAt(DirectX::XMVECTOR{ 0.0f, 0.0f, 0.0f, 1.0f });
		this->m_Camera->SetCameraPos(DirectX::XMVECTOR{ 0.0f, 0.0f, -1.0f, 1.0f });
		this->m_Camera->UpdateView();
}

void EditorInputHandler::UpdateMouse()
{
	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);
	this->m_mouse.x = this->m_point.x();
	this->m_mouse.y = this->m_point.y();
	if (this->m_mouse.x > this->m_Width)
		this->m_mouse.x = this->m_Width;
	else if (this->m_mouse.x < 0)
		this->m_mouse.x = 0;
	if (this->m_mouse.y > this->m_Height)
		this->m_mouse.y = this->m_Height;
	else if (this->m_mouse.y < 0)
		this->m_mouse.y = 0;

	if (this->m_mouse.leftHeld)
	{
		SelectionHandler::GetInstance()->ProjectRay(m_mouse.x, m_mouse.y);
		SelectionHandler::GetInstance()->MoveObject(m_KeysHeld[Bools::CONTROL]);
	}
}

void EditorInputHandler::mouseButtonDown(QMouseEvent * evt)
{
	if (evt->button() == Qt::LeftButton)
	{
		////*MOUSEPICKING*//
		SelectionHandler::GetInstance()->ProjectRay(m_mouse.x, m_mouse.y);

		bool object = false;
		bool widget = false;

		if (SelectionHandler::GetInstance()->HasSelection())
		{
			widget = SelectionHandler::GetInstance()->PickTransformWidget();
		}
		if (!widget)
			object = SelectionHandler::GetInstance()->PickObjectSelection();

		if (object || widget)
		{
			SelectionHandler::GetInstance()->SetSelection(true);
		}
		else if(!this->m_KeysHeld[ALT])
		{
			SelectionHandler::GetInstance()->SetSelection(false);
		}

		this->m_mouse.leftHeld = true;
	}
}

void EditorInputHandler::mouseButtonRelease(QMouseEvent * evt)
{
	if (evt->button() == Qt::LeftButton)
	{
		this->m_mouse.leftHeld = false;
		SelectionHandler::GetInstance()->SetActiveAxis(TransformWidget::NONE);
	}
}

void EditorInputHandler::keyReleased(QKeyEvent * evt)
{

		switch (evt->key())
		{
		case Qt::Key_Shift:
			m_KeysHeld[Bools::SHIFT] = false;
			break;
		case Qt::Key_Alt:
			m_KeysHeld[Bools::ALT] = false;
			break;
		case Qt::Key_Control:
			m_KeysHeld[Bools::CONTROL] = false;
			m_ableToDuplicate = true;
			break;
		case Qt::Key_W:
			m_KeysHeld[Bools::W] = false;
			break;
		case Qt::Key_A:
			m_KeysHeld[Bools::A] = false;
			break;
		case Qt::Key_S:
			m_KeysHeld[Bools::S] = false;
			break;
		case Qt::Key_D:
			m_KeysHeld[Bools::D] = false;
			break;
		case Qt::Key_C:
			m_KeysHeld[Bools::C] = false;
			break;
		case Qt::Key_Space:
			m_KeysHeld[Bools::SPACE] = false;
			break;
		default:
			break;
		}
}

void EditorInputHandler::ViewPortChanged(float height, float width)
{
	this->m_Height = height;
	this->m_Width  = width;

	SelectionHandler::GetInstance()->updateWindowSize(height, width);
}

void EditorInputHandler::deleteModel()
{
	if (SelectionHandler::GetInstance()->HasSelection())
	{
		LevelHandler::GetInstance()->GetCurrentLevel()->RemoveModel
			(SelectionHandler::GetInstance()->GetModelID(), SelectionHandler::GetInstance()->GetInstanceID());
		SelectionHandler::GetInstance()->SetSelection(false);
	}
}

void EditorInputHandler::detectInput(double dT, QKeyEvent* evt)
{
		switch (evt->key())
		{
		case Qt::Key_Shift:
			m_KeysHeld[Bools::SHIFT] = true;
			break;
		case Qt::Key_Alt:
			m_KeysHeld[Bools::ALT] = true;
			break;
		case Qt::Key_Control:
			m_KeysHeld[Bools::CONTROL] = true;
			break;
		case Qt::Key_W:
			m_KeysHeld[Bools::W] = true;
			break;
		case Qt::Key_A:
				m_KeysHeld[Bools::A] = true;
			break;
		case Qt::Key_S:
				m_KeysHeld[Bools::S] = true;
			break;
		case Qt::Key_D:
			if (m_ableToDuplicate)
			{
				if (this->m_KeysHeld[Bools::CONTROL] == true)
				{

						if (SelectionHandler::GetInstance()->HasSelection())
						{
							Container* temp = SelectionHandler::GetInstance()->GetSelected();
							Container* newEntity = nullptr;
							Resources::Status st = LevelHandler::GetInstance()->GetCurrentLevel()->DuplicateEntity(temp, newEntity);
							if (st == Resources::Status::ST_OK)
								SelectionHandler::GetInstance()->SetSelectedContainer(newEntity);
						}
						m_ableToDuplicate = false;
				}
			}
			m_KeysHeld[Bools::D] = true;
			break;

		case Qt::Key_C:
				m_KeysHeld[Bools::C] = true;
			break;
		case Qt::Key_Space:
				m_KeysHeld[Bools::SPACE] = true;
			break;
		case Qt::Key_R:
			CameraReset();
			break;
		case Qt::Key_Delete:
			deleteModel();
			break;
		case (Qt::Key_0):
		case (Qt::Key_Up) :
		case (Qt::Key_Down) :
		case (Qt::Key_Left) :
		case (Qt::Key_Right) :
			SelectionHandler::GetInstance()->RotateObject(evt->key());
			break;

		default:
			break;
		}

		/*switch (evt->key())
		{
		case Qt::Key_R:
			CameraReset();
			break;
		case (Qt::Key_Up):
		case (Qt::Key_Down):
		case (Qt::Key_Left):
		case (Qt::Key_Right):
			SelectionHandler::GetInstance()->RotateObject(evt->key());
			break;
		default:
			break;
		}*/
}<commit_msg>UPDATE works<commit_after>#include "EditorInputHandler.h"

EditorInputHandler::EditorInputHandler(
	HINSTANCE handleInstance,
	HWND handle,
	Camera* camera,
	int w,
	int h)
{
	this->m_Width = w;
	this->m_Height = h;
	HRESULT hr = DirectInput8Create(
		handleInstance,
		DIRECTINPUT_VERSION,
		IID_IDirectInput8,
		(void**)&m_directInput,
		NULL);

	//hr = m_directInput->CreateDevice(GUID_SysKeyboard,
	//	&DIKeyboard,
	//	NULL);

	hr = m_directInput->CreateDevice(GUID_SysMouse,
		&DIMouse,
		NULL);

	//hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
	//hr = DIKeyboard->SetCooperativeLevel(handle, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

	hr = DIMouse->SetDataFormat(&c_dfDIMouse);
	hr = DIMouse->SetCooperativeLevel(handle, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND);
	//this->m_hwnd	    = handle;
	this->m_Camera	    = camera;

	this->m_PreviousPos = camera->GetCameraPos();
	for (size_t i = 0; i < NUMBOOLS; i++)
	{
		this->m_KeysHeld[i] = false;
	}
	DIMouse->Acquire();

}

EditorInputHandler::~EditorInputHandler()
{
}

void EditorInputHandler::KeyboardMovement(double dT)
{
	float speed = 4.0f * dT;
	float translateCameraX = 0, translateCameraY = 0, translateCameraZ = 0;
	if (m_KeysHeld[Bools::SHIFT] == true)
	{
		if (this->m_KeysHeld[Bools::W] == true)
			translateCameraZ += speed;

		if (this->m_KeysHeld[Bools::A] == true)
			translateCameraX -= speed;
		if (this->m_KeysHeld[Bools::S] == true)
			translateCameraZ -= speed;
		if (this->m_KeysHeld[Bools::D] == true)
			translateCameraX += speed;
		if (this->m_KeysHeld[Bools::C] == true)
			translateCameraY -= speed;
		if (this->m_KeysHeld[Bools::SPACE] == true)
			translateCameraY -= speed;

			MouseZoom(dT);
	}
	else {
	if (this->m_KeysHeld[Bools::SPACE] == true)
		translateCameraY += speed;
	}
	if (this->m_KeysHeld[ALT] == true)
		MouseMovement(dT);

	if ((translateCameraY || translateCameraZ || translateCameraX))
	{
		DirectX::XMFLOAT3 posTranslation =
			DirectX::XMFLOAT3(
				float(translateCameraX),
				float(translateCameraY),
				float(translateCameraZ)
			);

		this->m_PreviousPos = this->m_Camera->GetCameraPos();
		this->m_Camera->ApplyLocalTranslation(
			float(translateCameraX),
			float(translateCameraY),
			float(translateCameraZ)
		);
		this->m_Camera->UpdateView();
	}
}

void EditorInputHandler::MouseMovement(double dT)
{
	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);
	float pitch = 0;
	float yaw = 0;
	float rotationAmount = (DirectX::XM_PI / 8) / 2;

		if (m_mouse.currentState.rgbButtons[0])
		{
			if ((m_mouse.currentState.lX != m_mouse.lastState.lX) || (m_mouse.currentState.lY != m_mouse.lastState.lY))
			{
				pitch += m_mouse.currentState.lX * 0.01f;

				yaw += m_mouse.currentState.lY * 0.01f;

				// Ensure the mouse location doesn't exceed the screen width or height.
				if (this->m_mouse.x < 0) { this->m_mouse.x = 0; }
				if (this->m_mouse.y < 0) { this->m_mouse.y = 0; }

				if (this->m_mouse.x > m_Width) { this->m_mouse.x = m_Width; }
				if (this->m_mouse.y > m_Height) { this->m_mouse.y = m_Height; }

				m_mouse.lastState = m_mouse.currentState;
			}
		}

	DirectX::XMFLOAT4 camUpFloat;
	DirectX::XMFLOAT3 camPosFloat;
	DirectX::XMFLOAT3 camTargetFloat;
	this->m_Camera->GetCameraUp(camUpFloat);
	camPosFloat = this->m_Camera->GetCameraPos();
	camTargetFloat = this->m_Camera->GetLookAt();

	DirectX::XMVECTOR rotationVector;

	DirectX::XMVECTOR camUpVec = { 0.0f, 1.0f,0.0f,0.0f };//DirectX::XMLoadFloat4(&camUpFloat);
	DirectX::XMVECTOR camPosVec = DirectX::XMLoadFloat3(&camPosFloat);
	DirectX::XMVECTOR camTargetVec = DirectX::XMLoadFloat3(&camTargetFloat);

	DirectX::XMVECTOR camDir = DirectX::XMVector3Normalize(DirectX::XMVectorSubtract(camTargetVec, camPosVec));

	DirectX::XMVECTOR camRight = DirectX::XMVector3Normalize(DirectX::XMVector3Cross(camDir, camUpVec));

	camRight.m128_f32[3] = rotationAmount * -yaw;
	camUpVec.m128_f32[3] = rotationAmount * pitch;

	if (pitch||yaw)
	{
		this->m_Camera->RotateCamera(camRight);
		this->m_Camera->RotateCamera(camUpVec);
	};

	this->m_Camera->UpdateView();
}

void EditorInputHandler::MouseZoom(double dT)
{

	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);

	float speedrot = 2.5f * dT;
	float translateCameraZ = 0;

	if (m_mouse.currentState.rgbButtons[0])
	{
		if (m_mouse.currentState.lY < 0)
		{
			translateCameraZ += speedrot;
		}
		if (m_mouse.currentState.lY > 0)
		{
			translateCameraZ -= speedrot;
		}

	}
	if (translateCameraZ)
	{
		DirectX::XMFLOAT3 posTranslation =
			DirectX::XMFLOAT3(
				0.0f,
				0.0f,
				float(translateCameraZ)
			);

		this->m_PreviousPos = this->m_Camera->GetCameraPos();
		this->m_Camera->ApplyLocalTranslation(
			0.0f,
			0.0f,
			float(translateCameraZ)
		);
		this->m_Camera->UpdateView();
	}
}

void EditorInputHandler::CameraReset()
{
		this->m_Camera->Initialize(this->m_Width / this->m_Height);
		this->m_Camera->SetLookAt(DirectX::XMVECTOR{ 0.0f, 0.0f, 0.0f, 1.0f });
		this->m_Camera->SetCameraPos(DirectX::XMVECTOR{ 0.0f, 0.0f, -1.0f, 1.0f });
		this->m_Camera->UpdateView();
}

void EditorInputHandler::UpdateMouse()
{
	DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouse.currentState);
	this->m_mouse.x = this->m_point.x();
	this->m_mouse.y = this->m_point.y();
	if (this->m_mouse.x > this->m_Width)
		this->m_mouse.x = this->m_Width;
	else if (this->m_mouse.x < 0)
		this->m_mouse.x = 0;
	if (this->m_mouse.y > this->m_Height)
		this->m_mouse.y = this->m_Height;
	else if (this->m_mouse.y < 0)
		this->m_mouse.y = 0;

	if (this->m_mouse.leftHeld)
	{
		SelectionHandler::GetInstance()->ProjectRay(m_mouse.x, m_mouse.y);
		SelectionHandler::GetInstance()->MoveObject(m_KeysHeld[Bools::CONTROL]);
	}
}

void EditorInputHandler::mouseButtonDown(QMouseEvent * evt)
{
	if (evt->button() == Qt::LeftButton && !this->m_KeysHeld[ALT])
	{
		////*MOUSEPICKING*//
		SelectionHandler::GetInstance()->ProjectRay(m_mouse.x, m_mouse.y);

		bool object = false;
		bool widget = false;

		if (SelectionHandler::GetInstance()->HasSelection() )
		{
			widget = SelectionHandler::GetInstance()->PickTransformWidget();
		}
		if (!widget)
			object = SelectionHandler::GetInstance()->PickObjectSelection();

		if (object || widget)
		{
			SelectionHandler::GetInstance()->SetSelection(true);
		}
		else if(!this->m_KeysHeld[ALT])
		{
			SelectionHandler::GetInstance()->SetSelection(false);
		}

		this->m_mouse.leftHeld = true;
	}
}

void EditorInputHandler::mouseButtonRelease(QMouseEvent * evt)
{
	if (evt->button() == Qt::LeftButton)
	{
		this->m_mouse.leftHeld = false;
		SelectionHandler::GetInstance()->SetActiveAxis(TransformWidget::NONE);
	}
}

void EditorInputHandler::keyReleased(QKeyEvent * evt)
{

		switch (evt->key())
		{
		case Qt::Key_Shift:
			m_KeysHeld[Bools::SHIFT] = false;
			break;
		case Qt::Key_Alt:
			m_KeysHeld[Bools::ALT] = false;
			break;
		case Qt::Key_Control:
			m_KeysHeld[Bools::CONTROL] = false;
			m_ableToDuplicate = true;
			break;
		case Qt::Key_W:
			m_KeysHeld[Bools::W] = false;
			break;
		case Qt::Key_A:
			m_KeysHeld[Bools::A] = false;
			break;
		case Qt::Key_S:
			m_KeysHeld[Bools::S] = false;
			break;
		case Qt::Key_D:
			m_KeysHeld[Bools::D] = false;
			break;
		case Qt::Key_C:
			m_KeysHeld[Bools::C] = false;
			break;
		case Qt::Key_Space:
			m_KeysHeld[Bools::SPACE] = false;
			break;
		default:
			break;
		}
}

void EditorInputHandler::ViewPortChanged(float height, float width)
{
	this->m_Height = height;
	this->m_Width  = width;

	SelectionHandler::GetInstance()->updateWindowSize(height, width);
}

void EditorInputHandler::deleteModel()
{
	if (SelectionHandler::GetInstance()->HasSelection())
	{
		LevelHandler::GetInstance()->GetCurrentLevel()->RemoveModel
			(SelectionHandler::GetInstance()->GetModelID(), SelectionHandler::GetInstance()->GetInstanceID());
		SelectionHandler::GetInstance()->SetSelection(false);
	}
}

void EditorInputHandler::detectInput(double dT, QKeyEvent* evt)
{
		switch (evt->key())
		{
		case Qt::Key_Shift:
			m_KeysHeld[Bools::SHIFT] = true;
			break;
		case Qt::Key_Alt:
			m_KeysHeld[Bools::ALT] = true;
			break;
		case Qt::Key_Control:
			m_KeysHeld[Bools::CONTROL] = true;
			break;
		case Qt::Key_W:
			m_KeysHeld[Bools::W] = true;
			break;
		case Qt::Key_A:
				m_KeysHeld[Bools::A] = true;
			break;
		case Qt::Key_S:
				m_KeysHeld[Bools::S] = true;
			break;
		case Qt::Key_D:
			if (m_ableToDuplicate)
			{
				if (this->m_KeysHeld[Bools::CONTROL] == true)
				{

						if (SelectionHandler::GetInstance()->HasSelection())
						{
							Container* temp = SelectionHandler::GetInstance()->GetSelected();
							Container* newEntity = nullptr;
							Resources::Status st = LevelHandler::GetInstance()->GetCurrentLevel()->DuplicateEntity(temp, newEntity);
							if (st == Resources::Status::ST_OK)
								SelectionHandler::GetInstance()->SetSelectedContainer(newEntity);
						}
						m_ableToDuplicate = false;
				}
			}
			m_KeysHeld[Bools::D] = true;
			break;

		case Qt::Key_C:
				m_KeysHeld[Bools::C] = true;
			break;
		case Qt::Key_Space:
				m_KeysHeld[Bools::SPACE] = true;
			break;
		case Qt::Key_R:
			CameraReset();
			break;
		case Qt::Key_Delete:
			deleteModel();
			break;
		case (Qt::Key_0):
		case (Qt::Key_Up) :
		case (Qt::Key_Down) :
		case (Qt::Key_Left) :
		case (Qt::Key_Right) :
			SelectionHandler::GetInstance()->RotateObject(evt->key());
			break;

		default:
			break;
		}

		/*switch (evt->key())
		{
		case Qt::Key_R:
			CameraReset();
			break;
		case (Qt::Key_Up):
		case (Qt::Key_Down):
		case (Qt::Key_Left):
		case (Qt::Key_Right):
			SelectionHandler::GetInstance()->RotateObject(evt->key());
			break;
		default:
			break;
		}*/
}<|endoftext|>


<commit_before>/*     Copyright 2015-2019 Egor Yusov
 *
 *  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 OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */
#include <X11/Xlib.h>
#include <X11/Xutil.h>

// Undef symbols defined by XLib
#ifdef Bool
#    undef Bool
#endif
#ifdef True
#    undef True
#endif
#ifdef False
#    undef False
#endif

#include <xcb/xcb.h>
#include "xcb_keysyms/xcb_keysyms.h"

#include "InputController.h"
#include "DebugUtilities.h"

namespace Diligent
{

int InputControllerLinux::HandleKeyEvevnt(unsigned int keysym, bool IsKeyPressed)
{
    int  handled        = 0;
    auto UpdateKeyState = [&](InputKeys Key) //
    {
        auto& KeyState = m_Keys[static_cast<size_t>(Key)];
        if (IsKeyPressed)
        {
            KeyState &= ~INPUT_KEY_STATE_FLAG_KEY_WAS_DOWN;
            KeyState |= INPUT_KEY_STATE_FLAG_KEY_IS_DOWN;
        }
        else
        {
            KeyState &= ~INPUT_KEY_STATE_FLAG_KEY_IS_DOWN;
            KeyState |= INPUT_KEY_STATE_FLAG_KEY_WAS_DOWN;
        }
        handled = 1;
    };

    //if (event->xkey.state & ControlMask)
    //    UpdateKeyState(InputKeys::ControlDown);
    //if (event->xkey.state & ShiftMask)
    //    UpdateKeyState(InputKeys::ShiftDown);
    //if (event->xkey.state & Mod1Mask)
    //    UpdateKeyState(InputKeys::AltDown);

    switch (keysym)
    {
        case XK_Control_L:
        case XK_Control_R:
            UpdateKeyState(InputKeys::ControlDown);
            break;

        case XK_Shift_L:
        case XK_Shift_R:
            UpdateKeyState(InputKeys::ShiftDown);
            break;

        case XK_Alt_L:
        case XK_Alt_R:
            UpdateKeyState(InputKeys::AltDown);
            break;

        case XK_Up:
        case 'w':
        case 'W':
            UpdateKeyState(InputKeys::MoveForward);
            break;

        case XK_Down:
        case 's':
        case 'S':
            UpdateKeyState(InputKeys::MoveBackward);
            break;

        case XK_Right:
        case 'd':
        case 'D':
            UpdateKeyState(InputKeys::MoveRight);
            break;

        case XK_Left:
        case 'a':
        case 'A':
            UpdateKeyState(InputKeys::MoveLeft);
            break;

        case XK_Home:
            UpdateKeyState(InputKeys::Reset);
            break;

        case XK_Page_Up:
        case 'e':
        case 'E':
            UpdateKeyState(InputKeys::MoveUp);
            break;

        case XK_Page_Down:
        case 'q':
        case 'Q':
            UpdateKeyState(InputKeys::MoveDown);
            break;

        case XK_plus:
            UpdateKeyState(InputKeys::ZoomIn);
            break;

        case XK_minus:
            UpdateKeyState(InputKeys::ZoomOut);
            break;

#ifdef XK_KP_Home
        case XK_KP_Home:
            UpdateKeyState(InputKeys::Reset);
            break;
#endif

#ifdef XK_KP_Up
        case XK_KP_Up:
            UpdateKeyState(InputKeys::MoveForward);
            break;

        case XK_KP_Down:
            UpdateKeyState(InputKeys::MoveBackward);
            break;

        case XK_KP_Right:
            UpdateKeyState(InputKeys::MoveRight);
            break;

        case XK_KP_Left:
            UpdateKeyState(InputKeys::MoveLeft);
            break;

        case XK_KP_Page_Up:
            UpdateKeyState(InputKeys::MoveUp);
            break;

        case XK_KP_Page_Down:
            UpdateKeyState(InputKeys::MoveDown);
            break;
#endif
    }

    return handled;
}

int InputControllerLinux::HandleXEvent(void* xevent)
{
    auto* event = reinterpret_cast<XEvent*>(xevent);
    switch (event->type)
    {
        case KeyPress:
        case KeyRelease:
        {
            KeySym keysym;
            int    num_char = XLookupString((XKeyEvent*)event, nullptr, 0, &keysym, 0);
            return HandleKeyEvevnt(keysym, event->type == KeyPress);
        }

        case ButtonPress:
        {
            auto* xbe = reinterpret_cast<XButtonEvent*>(event);
            switch (xbe->button)
            {
                case Button1:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_LEFT;
                    break;

                case Button2:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case Button3:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_RIGHT;
                    break;

                case Button4:
                    m_MouseState.WheelDelta += 1;
                    break;

                case Button5:
                    m_MouseState.WheelDelta -= 1;
                    break;
            }
            return 1;
        }

        case ButtonRelease:
        {
            auto* xbe = reinterpret_cast<XButtonEvent*>(event);
            switch (xbe->button)
            {
                case Button1:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_LEFT;
                    break;

                case Button2:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case Button3:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_RIGHT;
                    break;
            }
            return 1;
        }

        case MotionNotify:
        {
            auto* xme = (XMotionEvent*)event;

            m_MouseState.PosX = static_cast<float>(xme->x);
            m_MouseState.PosY = static_cast<float>(xme->y);
            return 1;
        }

        default:
            break;
    }

    return 0;
}

void InputControllerLinux::InitXCBKeysms(void* connection)
{
    VERIFY_EXPR(m_XCBKeySymbols == nullptr);
    m_XCBKeySymbols = xcb_key_symbols_alloc(reinterpret_cast<xcb_connection_t*>(connection));
}

InputControllerLinux::~InputControllerLinux()
{
    if (m_XCBKeySymbols != nullptr)
    {
        xcb_key_symbols_free(reinterpret_cast<xcb_key_symbols_t*>(m_XCBKeySymbols));
    }
}

int InputControllerLinux::HandleXCBEvent(void* xcb_event)
{
    auto* event = reinterpret_cast<xcb_generic_event_t*>(xcb_event);

    const auto event_type = event->response_type & 0x7f;
    switch (event_type)
    {
        case XCB_MOTION_NOTIFY:
        {
            xcb_motion_notify_event_t* motion = (xcb_motion_notify_event_t*)event;

            m_MouseState.PosX = static_cast<float>(motion->event_x);
            m_MouseState.PosY = static_cast<float>(motion->event_y);
            return 1;
        }
        break;

        case XCB_BUTTON_PRESS:
        {
            xcb_button_press_event_t* press = (xcb_button_press_event_t*)event;
            switch (press->detail)
            {
                case XCB_BUTTON_INDEX_1:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_LEFT;
                    break;

                case XCB_BUTTON_INDEX_2:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case XCB_BUTTON_INDEX_3:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_RIGHT;
                    break;

                case XCB_BUTTON_INDEX_4:
                    m_MouseState.WheelDelta += 1;
                    break;

                case XCB_BUTTON_INDEX_5:
                    m_MouseState.WheelDelta -= 1;
                    break;
            }
            return 1;
        }
        break;

        case XCB_BUTTON_RELEASE:
        {
            xcb_button_release_event_t* press = (xcb_button_release_event_t*)event;
            switch (press->detail)
            {
                case XCB_BUTTON_INDEX_1:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_LEFT;
                    break;

                case XCB_BUTTON_INDEX_2:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case XCB_BUTTON_INDEX_3:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_RIGHT;
                    break;
            }
            return 1;
        }
        break;

        case XCB_KEY_PRESS:
        case XCB_KEY_RELEASE:
        {
            xcb_keysym_t keysym = xcb_key_press_lookup_keysym(
                reinterpret_cast<xcb_key_symbols_t*>(m_XCBKeySymbols),
                reinterpret_cast<xcb_key_press_event_t*>(event), 0);
            return HandleKeyEvevnt(keysym, event_type == XCB_KEY_PRESS);
        }
        break;

        default:
            break;
    }

    return 0;
}

} // namespace Diligent
<commit_msg>Fixed linux build problem<commit_after>/*     Copyright 2015-2019 Egor Yusov
 *
 *  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 OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */
#include <X11/Xlib.h>
#include <X11/Xutil.h>

// Undef symbols defined by XLib
#ifdef Bool
#    undef Bool
#endif
#ifdef True
#    undef True
#endif
#ifdef False
#    undef False
#endif

#include <xcb/xcb.h>
#include "xcb_keysyms/xcb_keysyms.h"

#include "InputController.h"
#include "DebugUtilities.hpp"

namespace Diligent
{

int InputControllerLinux::HandleKeyEvevnt(unsigned int keysym, bool IsKeyPressed)
{
    int  handled        = 0;
    auto UpdateKeyState = [&](InputKeys Key) //
    {
        auto& KeyState = m_Keys[static_cast<size_t>(Key)];
        if (IsKeyPressed)
        {
            KeyState &= ~INPUT_KEY_STATE_FLAG_KEY_WAS_DOWN;
            KeyState |= INPUT_KEY_STATE_FLAG_KEY_IS_DOWN;
        }
        else
        {
            KeyState &= ~INPUT_KEY_STATE_FLAG_KEY_IS_DOWN;
            KeyState |= INPUT_KEY_STATE_FLAG_KEY_WAS_DOWN;
        }
        handled = 1;
    };

    //if (event->xkey.state & ControlMask)
    //    UpdateKeyState(InputKeys::ControlDown);
    //if (event->xkey.state & ShiftMask)
    //    UpdateKeyState(InputKeys::ShiftDown);
    //if (event->xkey.state & Mod1Mask)
    //    UpdateKeyState(InputKeys::AltDown);

    switch (keysym)
    {
        case XK_Control_L:
        case XK_Control_R:
            UpdateKeyState(InputKeys::ControlDown);
            break;

        case XK_Shift_L:
        case XK_Shift_R:
            UpdateKeyState(InputKeys::ShiftDown);
            break;

        case XK_Alt_L:
        case XK_Alt_R:
            UpdateKeyState(InputKeys::AltDown);
            break;

        case XK_Up:
        case 'w':
        case 'W':
            UpdateKeyState(InputKeys::MoveForward);
            break;

        case XK_Down:
        case 's':
        case 'S':
            UpdateKeyState(InputKeys::MoveBackward);
            break;

        case XK_Right:
        case 'd':
        case 'D':
            UpdateKeyState(InputKeys::MoveRight);
            break;

        case XK_Left:
        case 'a':
        case 'A':
            UpdateKeyState(InputKeys::MoveLeft);
            break;

        case XK_Home:
            UpdateKeyState(InputKeys::Reset);
            break;

        case XK_Page_Up:
        case 'e':
        case 'E':
            UpdateKeyState(InputKeys::MoveUp);
            break;

        case XK_Page_Down:
        case 'q':
        case 'Q':
            UpdateKeyState(InputKeys::MoveDown);
            break;

        case XK_plus:
            UpdateKeyState(InputKeys::ZoomIn);
            break;

        case XK_minus:
            UpdateKeyState(InputKeys::ZoomOut);
            break;

#ifdef XK_KP_Home
        case XK_KP_Home:
            UpdateKeyState(InputKeys::Reset);
            break;
#endif

#ifdef XK_KP_Up
        case XK_KP_Up:
            UpdateKeyState(InputKeys::MoveForward);
            break;

        case XK_KP_Down:
            UpdateKeyState(InputKeys::MoveBackward);
            break;

        case XK_KP_Right:
            UpdateKeyState(InputKeys::MoveRight);
            break;

        case XK_KP_Left:
            UpdateKeyState(InputKeys::MoveLeft);
            break;

        case XK_KP_Page_Up:
            UpdateKeyState(InputKeys::MoveUp);
            break;

        case XK_KP_Page_Down:
            UpdateKeyState(InputKeys::MoveDown);
            break;
#endif
    }

    return handled;
}

int InputControllerLinux::HandleXEvent(void* xevent)
{
    auto* event = reinterpret_cast<XEvent*>(xevent);
    switch (event->type)
    {
        case KeyPress:
        case KeyRelease:
        {
            KeySym keysym;
            int    num_char = XLookupString((XKeyEvent*)event, nullptr, 0, &keysym, 0);
            return HandleKeyEvevnt(keysym, event->type == KeyPress);
        }

        case ButtonPress:
        {
            auto* xbe = reinterpret_cast<XButtonEvent*>(event);
            switch (xbe->button)
            {
                case Button1:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_LEFT;
                    break;

                case Button2:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case Button3:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_RIGHT;
                    break;

                case Button4:
                    m_MouseState.WheelDelta += 1;
                    break;

                case Button5:
                    m_MouseState.WheelDelta -= 1;
                    break;
            }
            return 1;
        }

        case ButtonRelease:
        {
            auto* xbe = reinterpret_cast<XButtonEvent*>(event);
            switch (xbe->button)
            {
                case Button1:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_LEFT;
                    break;

                case Button2:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case Button3:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_RIGHT;
                    break;
            }
            return 1;
        }

        case MotionNotify:
        {
            auto* xme = (XMotionEvent*)event;

            m_MouseState.PosX = static_cast<float>(xme->x);
            m_MouseState.PosY = static_cast<float>(xme->y);
            return 1;
        }

        default:
            break;
    }

    return 0;
}

void InputControllerLinux::InitXCBKeysms(void* connection)
{
    VERIFY_EXPR(m_XCBKeySymbols == nullptr);
    m_XCBKeySymbols = xcb_key_symbols_alloc(reinterpret_cast<xcb_connection_t*>(connection));
}

InputControllerLinux::~InputControllerLinux()
{
    if (m_XCBKeySymbols != nullptr)
    {
        xcb_key_symbols_free(reinterpret_cast<xcb_key_symbols_t*>(m_XCBKeySymbols));
    }
}

int InputControllerLinux::HandleXCBEvent(void* xcb_event)
{
    auto* event = reinterpret_cast<xcb_generic_event_t*>(xcb_event);

    const auto event_type = event->response_type & 0x7f;
    switch (event_type)
    {
        case XCB_MOTION_NOTIFY:
        {
            xcb_motion_notify_event_t* motion = (xcb_motion_notify_event_t*)event;

            m_MouseState.PosX = static_cast<float>(motion->event_x);
            m_MouseState.PosY = static_cast<float>(motion->event_y);
            return 1;
        }
        break;

        case XCB_BUTTON_PRESS:
        {
            xcb_button_press_event_t* press = (xcb_button_press_event_t*)event;
            switch (press->detail)
            {
                case XCB_BUTTON_INDEX_1:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_LEFT;
                    break;

                case XCB_BUTTON_INDEX_2:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case XCB_BUTTON_INDEX_3:
                    m_MouseState.ButtonFlags |= MouseState::BUTTON_FLAG_RIGHT;
                    break;

                case XCB_BUTTON_INDEX_4:
                    m_MouseState.WheelDelta += 1;
                    break;

                case XCB_BUTTON_INDEX_5:
                    m_MouseState.WheelDelta -= 1;
                    break;
            }
            return 1;
        }
        break;

        case XCB_BUTTON_RELEASE:
        {
            xcb_button_release_event_t* press = (xcb_button_release_event_t*)event;
            switch (press->detail)
            {
                case XCB_BUTTON_INDEX_1:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_LEFT;
                    break;

                case XCB_BUTTON_INDEX_2:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_MIDDLE;
                    break;

                case XCB_BUTTON_INDEX_3:
                    m_MouseState.ButtonFlags &= ~MouseState::BUTTON_FLAG_RIGHT;
                    break;
            }
            return 1;
        }
        break;

        case XCB_KEY_PRESS:
        case XCB_KEY_RELEASE:
        {
            xcb_keysym_t keysym = xcb_key_press_lookup_keysym(
                reinterpret_cast<xcb_key_symbols_t*>(m_XCBKeySymbols),
                reinterpret_cast<xcb_key_press_event_t*>(event), 0);
            return HandleKeyEvevnt(keysym, event_type == XCB_KEY_PRESS);
        }
        break;

        default:
            break;
    }

    return 0;
}

} // namespace Diligent
<|endoftext|>


<commit_before>//
// Created by bentoo on 13.02.17.
//

#include <Core/Input/InputEvent.h>
#include <Core/EventQueue.h>
#include "Core/Input/InputManager.h"
#include "Core/Input/ControlScheme.h"
#include "Core/Input/InputEvent.h"
#include "Core/Platform.h"
#include "Core/Logger.h"

namespace Core
{
	InputDevice::InputDevice(Memory::IMemoryBlock& memory, std::int32_t deviceId)
		: name(memory, glfwGetJoystickName(deviceId)),
		  scheme(nullptr), type(Input::DeviceType::CONTROLLER)
	{ }

	InputDevice::~InputDevice()
	{ }

	InputManager::~InputManager()
	{
		for(auto itr : _controllerIdMap)
		{
			Memory::Delete(_memory, itr.second);
			itr.second = nullptr;
		}
	}

	InputDevice* InputManager::getDeviceForId(std::int32_t id)
	{
		InputDevice*	result	= nullptr;
		auto			itr		= _controllerIdMap.find(id);

		if(itr != _controllerIdMap.end())
		{
			result = itr->second;
		}

		return result;
	}

	InputDevice* InputManager::getDeviceForEvent(const Input::InputEvent& event)
	{
		InputDevice* result = nullptr;

		switch(event.deviceType)
		{
			case Input::DeviceType::MOUSE:
				result = &Mouse;
				break;
			case Input::DeviceType::KEYBOARD:
				result = &Keyboard;
				break;
			case Input::DeviceType::CONTROLLER:
				result = getDeviceForId(event.deviceId);
				break;
			default:
				Logger::warn("InputManager : Unknown device '%zu'", (uint) event.deviceType);
				break;
		}

		return result;
	}

	auto InputManager::getSchemeForDevice(InputDevice* device) -> Input::ControlScheme*
	{
		if(device == nullptr)
			return nullptr;

		return device->scheme != nullptr ? device->scheme : _currentScheme;
	}

	void InputManager::onDeviceDisconnected(const Input::ConnectionEvent& event)
	{
		auto device = getDeviceForId(event.deviceId);
		if(device != nullptr)
		{
			Core::Logger::debug("Controller : Disconnected '{}', named '{}'.",
								device->id, device->name.c_str());

			_controllerIdMap.erase(device->id);
			Memory::Delete(_memory, device);
		}
	}

	void InputManager::onDeviceConnected(const Input::ConnectionEvent& event)
	{
		if(event.deviceId == Input::DeviceType::CONTROLLER
	   	&& glfwJoystickPresent(event.deviceId))
		{
			auto inputDevice = YAGE_CREATE_NEW(_memory, InputDevice)(_memory, event.deviceId);

			Core::Logger::debug("Controller : Connected '{}', named '{}'.",
								event.deviceId, inputDevice->name.c_str());

			_controllerIdMap[event.deviceId] = inputDevice;
		}
	}

	void InputManager::onKey(InputDevice* device, std::int32_t scancode, std::int32_t state, Core::GameTime& time)
	{
		Input::ControlScheme* scheme = getSchemeForDevice(device);
		if(scheme != nullptr)
		{
			scheme->updateButtonByScancode(device->type, scancode, state, time);
		}
	}

	void InputManager::onAxis(InputDevice* device, std::int32_t axis, std::int32_t x, std::int32_t y, Core::GameTime& time)
	{
		Input::ControlScheme* scheme = getSchemeForDevice(device);
		if(scheme != nullptr)
		{
		//	scheme->updateAxisById(device->type, axis, x, y, time);
		}
	}

	void InputManager::handleInputEvent(const Core::Event& event, Core::GameTime& time)
	{
		auto input  = event.inputData;
		auto device = getDeviceForEvent(input);

		switch(input.type)
		{
			case Input::EventType::BUTTON:
				onKey(device, input.button.scancode, input.button.status, time);
				break;
			case Input::EventType::AXIS:
				onAxis(device, input.axis.axisId, input.axis.x, input.axis.y, time);
				break;
			case Input::EventType::CONNECTED:
				onDeviceConnected(input.connection);
				break;
			case Input::EventType::DISCONNECTED:
				onDeviceDisconnected(input.connection);
				break;
		}
	}
}
<commit_msg>Attempt to fix compiler complaint<commit_after>//
// Created by bentoo on 13.02.17.
//

#include <Core/Input/InputEvent.h>
#include <Core/EventQueue.h>
#include "Core/Input/InputManager.h"
#include "Core/Input/ControlScheme.h"
#include "Core/Input/InputEvent.h"
#include "Core/Platform.h"
#include "Core/Logger.h"

namespace Core
{
	InputDevice::InputDevice(Memory::IMemoryBlock& memory, std::int32_t deviceId)
		: name(memory, glfwGetJoystickName(deviceId)),
		  scheme(nullptr), type(Input::DeviceType::CONTROLLER)
	{ }

	InputDevice::~InputDevice()
	{ }

	InputManager::~InputManager()
	{
		for(auto itr : _controllerIdMap)
		{
			Memory::Delete(_memory, itr.second);
			itr.second = nullptr;
		}
	}

	InputDevice* InputManager::getDeviceForId(std::int32_t id)
	{
		InputDevice*	result	= nullptr;
		auto			itr		= _controllerIdMap.find(id);

		if(itr != _controllerIdMap.end())
		{
			result = itr->second;
		}

		return result;
	}

	InputDevice* InputManager::getDeviceForEvent(const Input::InputEvent& event)
	{
		InputDevice* result = nullptr;

		switch(event.deviceType)
		{
			case Input::DeviceType::MOUSE:
				result = &Mouse;
				break;
			case Input::DeviceType::KEYBOARD:
				result = &Keyboard;
				break;
			case Input::DeviceType::CONTROLLER:
				result = getDeviceForId(event.deviceId);
				break;
			default:
				Logger::warn("InputManager : Unknown device '%zu'", (unsigned int) event.deviceType);
				break;
		}

		return result;
	}

	auto InputManager::getSchemeForDevice(InputDevice* device) -> Input::ControlScheme*
	{
		if(device == nullptr)
			return nullptr;

		return device->scheme != nullptr ? device->scheme : _currentScheme;
	}

	void InputManager::onDeviceDisconnected(const Input::ConnectionEvent& event)
	{
		auto device = getDeviceForId(event.deviceId);
		if(device != nullptr)
		{
			Core::Logger::debug("Controller : Disconnected '{}', named '{}'.",
								device->id, device->name.c_str());

			_controllerIdMap.erase(device->id);
			Memory::Delete(_memory, device);
		}
	}

	void InputManager::onDeviceConnected(const Input::ConnectionEvent& event)
	{
		if(event.deviceId == Input::DeviceType::CONTROLLER
	   	&& glfwJoystickPresent(event.deviceId))
		{
			auto inputDevice = YAGE_CREATE_NEW(_memory, InputDevice)(_memory, event.deviceId);

			Core::Logger::debug("Controller : Connected '{}', named '{}'.",
								event.deviceId, inputDevice->name.c_str());

			_controllerIdMap[event.deviceId] = inputDevice;
		}
	}

	void InputManager::onKey(InputDevice* device, std::int32_t scancode, std::int32_t state, Core::GameTime& time)
	{
		Input::ControlScheme* scheme = getSchemeForDevice(device);
		if(scheme != nullptr)
		{
			scheme->updateButtonByScancode(device->type, scancode, state, time);
		}
	}

	void InputManager::onAxis(InputDevice* device, std::int32_t axis, std::int32_t x, std::int32_t y, Core::GameTime& time)
	{
		Input::ControlScheme* scheme = getSchemeForDevice(device);
		if(scheme != nullptr)
		{
		//	scheme->updateAxisById(device->type, axis, x, y, time);
		}
	}

	void InputManager::handleInputEvent(const Core::Event& event, Core::GameTime& time)
	{
		auto input  = event.inputData;
		auto device = getDeviceForEvent(input);

		switch(input.type)
		{
			case Input::EventType::BUTTON:
				onKey(device, input.button.scancode, input.button.status, time);
				break;
			case Input::EventType::AXIS:
				onAxis(device, input.axis.axisId, input.axis.x, input.axis.y, time);
				break;
			case Input::EventType::CONNECTED:
				onDeviceConnected(input.connection);
				break;
			case Input::EventType::DISCONNECTED:
				onDeviceDisconnected(input.connection);
				break;
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "platform/geometry/FloatPolygon.h"

#include <gtest/gtest.h>

namespace WebCore {

class FloatPolygonTestValue {
public:
    FloatPolygonTestValue(const float* coordinates, unsigned coordinatesLength, WindRule fillRule)
    {
        ASSERT(!(coordinatesLength % 2));
        OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(coordinatesLength / 2));
        for (unsigned i = 0; i < coordinatesLength; i += 2)
            (*vertices)[i / 2] = FloatPoint(coordinates[i], coordinates[i + 1]);
        m_polygon = adoptPtr(new FloatPolygon(vertices.release(), fillRule));
    }

    const FloatPolygon& polygon() const { return *m_polygon; }

private:
    OwnPtr<FloatPolygon> m_polygon;
};

} // namespace WebCore

namespace {

using namespace WebCore;

static bool compareEdgeIndex(const FloatPolygonEdge* edge1, const FloatPolygonEdge* edge2)
{
    return edge1->edgeIndex() < edge2->edgeIndex();
}

static Vector<const FloatPolygonEdge*> sortedOverlappingEdges(const FloatPolygon& polygon, float minY, float maxY)
{
    Vector<const FloatPolygonEdge*> result;
    polygon.overlappingEdges(minY, maxY, result);
    std::sort(result.begin(), result.end(), compareEdgeIndex);
    return result;
}

#define SIZEOF_ARRAY(p) (sizeof(p) / sizeof(p[0]))

/**
 * Checks a right triangle. This test covers all of the trivial FloatPolygon accessors.
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, basics)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_NONZERO, triangle.fillRule());
    EXPECT_FALSE(triangle.isEmpty());

    EXPECT_EQ(3u, triangle.numberOfVertices());
    EXPECT_EQ(FloatPoint(200, 100), triangle.vertexAt(0));
    EXPECT_EQ(FloatPoint(200, 200), triangle.vertexAt(1));
    EXPECT_EQ(FloatPoint(100, 200), triangle.vertexAt(2));

    EXPECT_EQ(3u, triangle.numberOfEdges());
    EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(0).vertex1());
    EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(0).vertex2());
    EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(1).vertex1());
    EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(1).vertex2());
    EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(2).vertex1());
    EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(2).vertex2());

    EXPECT_EQ(0u, triangle.edgeAt(0).vertexIndex1());
    EXPECT_EQ(1u, triangle.edgeAt(0).vertexIndex2());
    EXPECT_EQ(1u, triangle.edgeAt(1).vertexIndex1());
    EXPECT_EQ(2u, triangle.edgeAt(1).vertexIndex2());
    EXPECT_EQ(2u, triangle.edgeAt(2).vertexIndex1());
    EXPECT_EQ(0u, triangle.edgeAt(2).vertexIndex2());

    EXPECT_EQ(200, triangle.edgeAt(0).minX());
    EXPECT_EQ(200, triangle.edgeAt(0).maxX());
    EXPECT_EQ(100, triangle.edgeAt(1).minX());
    EXPECT_EQ(200, triangle.edgeAt(1).maxX());
    EXPECT_EQ(100, triangle.edgeAt(2).minX());
    EXPECT_EQ(200, triangle.edgeAt(2).maxX());

    EXPECT_EQ(100, triangle.edgeAt(0).minY());
    EXPECT_EQ(200, triangle.edgeAt(0).maxY());
    EXPECT_EQ(200, triangle.edgeAt(1).minY());
    EXPECT_EQ(200, triangle.edgeAt(1).maxY());
    EXPECT_EQ(100, triangle.edgeAt(2).minY());
    EXPECT_EQ(200, triangle.edgeAt(2).maxY());

    EXPECT_EQ(0u, triangle.edgeAt(0).edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(1).edgeIndex());
    EXPECT_EQ(2u, triangle.edgeAt(2).edgeIndex());

    EXPECT_EQ(2u, triangle.edgeAt(0).previousEdge().edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(0).nextEdge().edgeIndex());
    EXPECT_EQ(0u, triangle.edgeAt(1).previousEdge().edgeIndex());
    EXPECT_EQ(2u, triangle.edgeAt(1).nextEdge().edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(2).previousEdge().edgeIndex());
    EXPECT_EQ(0u, triangle.edgeAt(2).nextEdge().edgeIndex());

    EXPECT_EQ(FloatRect(100, 100, 100, 100), triangle.boundingBox());

    Vector<const FloatPolygonEdge*> resultA = sortedOverlappingEdges(triangle, 100, 200);
    EXPECT_EQ(3u, resultA.size());
    if (resultA.size() == 3) {
        EXPECT_EQ(0u, resultA[0]->edgeIndex());
        EXPECT_EQ(1u, resultA[1]->edgeIndex());
        EXPECT_EQ(2u, resultA[2]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultB = sortedOverlappingEdges(triangle, 200, 200);
    EXPECT_EQ(3u, resultB.size());
    if (resultB.size() == 3) {
        EXPECT_EQ(0u, resultB[0]->edgeIndex());
        EXPECT_EQ(1u, resultB[1]->edgeIndex());
        EXPECT_EQ(2u, resultB[2]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultC = sortedOverlappingEdges(triangle, 100, 150);
    EXPECT_EQ(2u, resultC.size());
    if (resultC.size() == 2) {
        EXPECT_EQ(0u, resultC[0]->edgeIndex());
        EXPECT_EQ(2u, resultC[1]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultD = sortedOverlappingEdges(triangle, 201, 300);
    EXPECT_EQ(0u, resultD.size());

    Vector<const FloatPolygonEdge*> resultE = sortedOverlappingEdges(triangle, 98, 99);
    EXPECT_EQ(0u, resultE.size());
}

/**
 * Tests FloatPolygon::contains() with a right triangle, and fillRule = nonzero.
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, triangle_nonzero)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_NONZERO, triangle.fillRule());
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 100)));
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(100, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(150, 150)));
    EXPECT_FALSE(triangle.contains(FloatPoint(100, 100)));
    EXPECT_FALSE(triangle.contains(FloatPoint(149, 149)));
    EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5)));
    EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5)));
}

/**
 * Tests FloatPolygon::contains() with a right triangle, and fillRule = evenodd;
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, triangle_evenodd)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_EVENODD);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_EVENODD, triangle.fillRule());
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 100)));
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(100, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(150, 150)));
    EXPECT_FALSE(triangle.contains(FloatPoint(100, 100)));
    EXPECT_FALSE(triangle.contains(FloatPoint(149, 149)));
    EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5)));
    EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5)));
}

} // namespace
<commit_msg>[CSS Shapes] Add FloatPolygon unit tests<commit_after>/*
 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "platform/geometry/FloatPolygon.h"

#include <gtest/gtest.h>

namespace WebCore {

class FloatPolygonTestValue {
public:
    FloatPolygonTestValue(const float* coordinates, unsigned coordinatesLength, WindRule fillRule)
    {
        ASSERT(!(coordinatesLength % 2));
        OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(coordinatesLength / 2));
        for (unsigned i = 0; i < coordinatesLength; i += 2)
            (*vertices)[i / 2] = FloatPoint(coordinates[i], coordinates[i + 1]);
        m_polygon = adoptPtr(new FloatPolygon(vertices.release(), fillRule));
    }

    const FloatPolygon& polygon() const { return *m_polygon; }

private:
    OwnPtr<FloatPolygon> m_polygon;
};

} // namespace WebCore

namespace {

using namespace WebCore;

static bool compareEdgeIndex(const FloatPolygonEdge* edge1, const FloatPolygonEdge* edge2)
{
    return edge1->edgeIndex() < edge2->edgeIndex();
}

static Vector<const FloatPolygonEdge*> sortedOverlappingEdges(const FloatPolygon& polygon, float minY, float maxY)
{
    Vector<const FloatPolygonEdge*> result;
    polygon.overlappingEdges(minY, maxY, result);
    std::sort(result.begin(), result.end(), compareEdgeIndex);
    return result;
}

#define SIZEOF_ARRAY(p) (sizeof(p) / sizeof(p[0]))

/**
 * Checks a right triangle. This test covers all of the trivial FloatPolygon accessors.
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, basics)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_NONZERO, triangle.fillRule());
    EXPECT_FALSE(triangle.isEmpty());

    EXPECT_EQ(3u, triangle.numberOfVertices());
    EXPECT_EQ(FloatPoint(200, 100), triangle.vertexAt(0));
    EXPECT_EQ(FloatPoint(200, 200), triangle.vertexAt(1));
    EXPECT_EQ(FloatPoint(100, 200), triangle.vertexAt(2));

    EXPECT_EQ(3u, triangle.numberOfEdges());
    EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(0).vertex1());
    EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(0).vertex2());
    EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(1).vertex1());
    EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(1).vertex2());
    EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(2).vertex1());
    EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(2).vertex2());

    EXPECT_EQ(0u, triangle.edgeAt(0).vertexIndex1());
    EXPECT_EQ(1u, triangle.edgeAt(0).vertexIndex2());
    EXPECT_EQ(1u, triangle.edgeAt(1).vertexIndex1());
    EXPECT_EQ(2u, triangle.edgeAt(1).vertexIndex2());
    EXPECT_EQ(2u, triangle.edgeAt(2).vertexIndex1());
    EXPECT_EQ(0u, triangle.edgeAt(2).vertexIndex2());

    EXPECT_EQ(200, triangle.edgeAt(0).minX());
    EXPECT_EQ(200, triangle.edgeAt(0).maxX());
    EXPECT_EQ(100, triangle.edgeAt(1).minX());
    EXPECT_EQ(200, triangle.edgeAt(1).maxX());
    EXPECT_EQ(100, triangle.edgeAt(2).minX());
    EXPECT_EQ(200, triangle.edgeAt(2).maxX());

    EXPECT_EQ(100, triangle.edgeAt(0).minY());
    EXPECT_EQ(200, triangle.edgeAt(0).maxY());
    EXPECT_EQ(200, triangle.edgeAt(1).minY());
    EXPECT_EQ(200, triangle.edgeAt(1).maxY());
    EXPECT_EQ(100, triangle.edgeAt(2).minY());
    EXPECT_EQ(200, triangle.edgeAt(2).maxY());

    EXPECT_EQ(0u, triangle.edgeAt(0).edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(1).edgeIndex());
    EXPECT_EQ(2u, triangle.edgeAt(2).edgeIndex());

    EXPECT_EQ(2u, triangle.edgeAt(0).previousEdge().edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(0).nextEdge().edgeIndex());
    EXPECT_EQ(0u, triangle.edgeAt(1).previousEdge().edgeIndex());
    EXPECT_EQ(2u, triangle.edgeAt(1).nextEdge().edgeIndex());
    EXPECT_EQ(1u, triangle.edgeAt(2).previousEdge().edgeIndex());
    EXPECT_EQ(0u, triangle.edgeAt(2).nextEdge().edgeIndex());

    EXPECT_EQ(FloatRect(100, 100, 100, 100), triangle.boundingBox());

    Vector<const FloatPolygonEdge*> resultA = sortedOverlappingEdges(triangle, 100, 200);
    EXPECT_EQ(3u, resultA.size());
    if (resultA.size() == 3) {
        EXPECT_EQ(0u, resultA[0]->edgeIndex());
        EXPECT_EQ(1u, resultA[1]->edgeIndex());
        EXPECT_EQ(2u, resultA[2]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultB = sortedOverlappingEdges(triangle, 200, 200);
    EXPECT_EQ(3u, resultB.size());
    if (resultB.size() == 3) {
        EXPECT_EQ(0u, resultB[0]->edgeIndex());
        EXPECT_EQ(1u, resultB[1]->edgeIndex());
        EXPECT_EQ(2u, resultB[2]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultC = sortedOverlappingEdges(triangle, 100, 150);
    EXPECT_EQ(2u, resultC.size());
    if (resultC.size() == 2) {
        EXPECT_EQ(0u, resultC[0]->edgeIndex());
        EXPECT_EQ(2u, resultC[1]->edgeIndex());
    }

    Vector<const FloatPolygonEdge*> resultD = sortedOverlappingEdges(triangle, 201, 300);
    EXPECT_EQ(0u, resultD.size());

    Vector<const FloatPolygonEdge*> resultE = sortedOverlappingEdges(triangle, 98, 99);
    EXPECT_EQ(0u, resultE.size());
}

/**
 * Tests FloatPolygon::contains() with a right triangle, and fillRule = nonzero.
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, triangle_nonzero)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_NONZERO, triangle.fillRule());
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 100)));
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(100, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(150, 150)));
    EXPECT_FALSE(triangle.contains(FloatPoint(100, 100)));
    EXPECT_FALSE(triangle.contains(FloatPoint(149, 149)));
    EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5)));
    EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5)));
}

/**
 * Tests FloatPolygon::contains() with a right triangle, and fillRule = evenodd;
 *
 *                        200,100
 *                          /|
 *                         / |
 *                        /  |
 *                       -----
 *                 100,200   200,200
 */
TEST(FloatPolygonTest, triangle_evenodd)
{
    const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200};
    FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_EVENODD);
    const FloatPolygon& triangle = triangleTestValue.polygon();

    EXPECT_EQ(RULE_EVENODD, triangle.fillRule());
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 100)));
    EXPECT_TRUE(triangle.contains(FloatPoint(200, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(100, 200)));
    EXPECT_TRUE(triangle.contains(FloatPoint(150, 150)));
    EXPECT_FALSE(triangle.contains(FloatPoint(100, 100)));
    EXPECT_FALSE(triangle.contains(FloatPoint(149, 149)));
    EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5)));
    EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5)));
}

#define TEST_EMPTY(coordinates)                                                                        \
{                                                                                \
    FloatPolygonTestValue emptyPolygonTestValue(coordinates, SIZEOF_ARRAY(coordinates), RULE_NONZERO); \
    const FloatPolygon& emptyPolygon = emptyPolygonTestValue.polygon();                                \
    EXPECT_TRUE(emptyPolygon.isEmpty());                                                               \
}

TEST(FloatPolygonTest, emptyPolygons)
{
    const float emptyCoordinates1[] = {0, 0};
    TEST_EMPTY(emptyCoordinates1);

    const float emptyCoordinates2[] = {0, 0, 1, 1};
    TEST_EMPTY(emptyCoordinates2);

    const float emptyCoordinates3[] = {0, 0, 1, 1, 2, 2, 3, 3};
    TEST_EMPTY(emptyCoordinates3);

    const float emptyCoordinates4[] = {0, 0, 1, 1, 2, 2, 3, 3, 1, 1};
    TEST_EMPTY(emptyCoordinates4);

    const float emptyCoordinates5[] = {0, 0, 0, 1, 0, 2, 0, 3, 0, 1};
    TEST_EMPTY(emptyCoordinates5);

    const float emptyCoordinates6[] = {0, 0, 1, 0, 2, 0, 3, 0, 1, 0};
    TEST_EMPTY(emptyCoordinates6);
}

/*
 * Test FloatPolygon::contains() with a trapezoid. The vertices are listed in counter-clockwise order.
 *
 *        150,100   250,100
 *          +----------+
 *         /            \
 *        /              \
 *       +----------------+
 *     100,150          300,150
 */
TEST(FloatPolygonTest, trapezoid)
{
    const float trapezoidCoordinates[] = {100, 150, 300, 150, 250, 100, 150, 100};
    FloatPolygonTestValue trapezoidTestValue(trapezoidCoordinates, SIZEOF_ARRAY(trapezoidCoordinates), RULE_EVENODD);
    const FloatPolygon& trapezoid = trapezoidTestValue.polygon();

    EXPECT_FALSE(trapezoid.isEmpty());
    EXPECT_EQ(4u, trapezoid.numberOfVertices());
    EXPECT_EQ(FloatRect(100, 100, 200, 50), trapezoid.boundingBox());

    EXPECT_TRUE(trapezoid.contains(FloatPoint(150, 100)));
    EXPECT_TRUE(trapezoid.contains(FloatPoint(150, 101)));
    EXPECT_TRUE(trapezoid.contains(FloatPoint(200, 125)));
    EXPECT_FALSE(trapezoid.contains(FloatPoint(149, 100)));
    EXPECT_FALSE(trapezoid.contains(FloatPoint(301, 150)));
}

/*
 * Test FloatPolygon::contains() with a non-convex rectilinear polygon. The polygon has the same shape
 * as the letter "H":
 *
 *    100,100  150,100   200,100   250,100
 *       +--------+        +--------+
 *       |        |        |        |
 *       |        |        |        |
 *       |        +--------+        |
 *       |     150,150   200,150    |
 *       |                          |
 *       |     150,200   200,200    |
 *       |        +--------+        |
 *       |        |        |        |
 *       |        |        |        |
 *       +--------+        +--------+
 *    100,250  150,250   200,250   250,250
 */
TEST(FloatPolygonTest, rectilinear)
{
    const float hCoordinates[] = {100, 100, 150, 100, 150, 150, 200, 150, 200, 100, 250, 100, 250, 250, 200, 250, 200, 200, 150, 200, 150, 250, 100, 250};
    FloatPolygonTestValue hTestValue(hCoordinates, SIZEOF_ARRAY(hCoordinates), RULE_NONZERO);
    const FloatPolygon& h = hTestValue.polygon();

    EXPECT_FALSE(h.isEmpty());
    EXPECT_EQ(12u, h.numberOfVertices());
    EXPECT_EQ(FloatRect(100, 100, 150, 150), h.boundingBox());

    EXPECT_TRUE(h.contains(FloatPoint(100, 100)));
    EXPECT_TRUE(h.contains(FloatPoint(125, 100)));
    EXPECT_TRUE(h.contains(FloatPoint(125, 125)));
    EXPECT_TRUE(h.contains(FloatPoint(150, 100)));
    EXPECT_TRUE(h.contains(FloatPoint(200, 200)));
    EXPECT_TRUE(h.contains(FloatPoint(225, 225)));
    EXPECT_TRUE(h.contains(FloatPoint(250, 250)));
    EXPECT_TRUE(h.contains(FloatPoint(100, 250)));
    EXPECT_TRUE(h.contains(FloatPoint(125, 250)));

    EXPECT_FALSE(h.contains(FloatPoint(99, 100)));
    EXPECT_FALSE(h.contains(FloatPoint(251, 100)));
    EXPECT_FALSE(h.contains(FloatPoint(151, 100)));
    EXPECT_FALSE(h.contains(FloatPoint(199, 100)));
    EXPECT_FALSE(h.contains(FloatPoint(175, 125)));
    EXPECT_FALSE(h.contains(FloatPoint(151, 250)));
    EXPECT_FALSE(h.contains(FloatPoint(199, 250)));
    EXPECT_FALSE(h.contains(FloatPoint(199, 250)));
    EXPECT_FALSE(h.contains(FloatPoint(175, 225)));
}

} // namespace
<|endoftext|>