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

#include "VaQuoleUILib.h"
#include "VaQuoleAppThread.h"

#include <QApplication>
#include <QDebug>

#include <QImage>
#include <QWebFrame>
#include <QString>
#include <QHash>

namespace VaQuole
{

/** Main app thread with QApplication */
static VaQuoleUIManager* pAppThread = NULL;

/** Key map to convert UE4 keys to Qt ones */
QHash<QString, Qt::Key> KeyMap;

/** Key map to convert UE4 keys to QString characters */
QHash<QString, QString> KeyTextMap;

/**
 * Key map to apply SHIFT modificator. Seemed as Qt bug,
 * Check https://bugreports.qt-project.org/browse/QTBUG-40100
 */
QHash<QString, QString> KeyShiftMap;

//////////////////////////////////////////////////////////////////////////
// Common lib functions

void Init()
{
	// Check that we haven't qApp already
	if (QApplication::instance() == nullptr)
	{
		pAppThread = new VaQuoleUIManager();
		pAppThread->start();
	}

	InitKeyMaps();
}

void Cleanup()
{
	qDebug() << "Clean so clean";

	if (pAppThread != NULL)
	{
		pAppThread->~VaQuoleUIManager();//->stop();
	}
}

VaQuoleWebUI* ConstructNewUI()
{
	VaQuoleWebUI* NewUI = new VaQuoleWebUI();
	NewUI->Register();

	return NewUI;
}

void InitKeyMaps()
{
	KeyMap.clear();

	KeyMap.insert("BackSpace", Qt::Key_Backspace);
	KeyMap.insert("Tab", Qt::Key_Tab);
	KeyMap.insert("Enter", Qt::Key_Enter);
	KeyMap.insert("Pause", Qt::Key_Pause);

	KeyMap.insert("CapsLock", Qt::Key_CapsLock);
	KeyMap.insert("Escape", Qt::Key_Escape);
	KeyMap.insert("SpaceBar", Qt::Key_Space);
	KeyMap.insert("PageUp", Qt::Key_PageUp);
	KeyMap.insert("PageDown", Qt::Key_PageDown);
	KeyMap.insert("End", Qt::Key_End);
	KeyMap.insert("Home", Qt::Key_Home);

	KeyMap.insert("Left", Qt::Key_Left);
	KeyMap.insert("Up", Qt::Key_Up);
	KeyMap.insert("Right", Qt::Key_Right);
	KeyMap.insert("Down", Qt::Key_Down);
	KeyMap.insert("Insert", Qt::Key_Insert);
	KeyMap.insert("Delete", Qt::Key_Delete);

	KeyMap.insert("NumPadZero", Qt::Key_0);
	KeyMap.insert("NumPadOne", Qt::Key_1);
	KeyMap.insert("NumPadTwo", Qt::Key_2);
	KeyMap.insert("NumPadThree", Qt::Key_3);
	KeyMap.insert("NumPadFour", Qt::Key_4);
	KeyMap.insert("NumPadFive", Qt::Key_5);
	KeyMap.insert("NumPadSix", Qt::Key_6);
	KeyMap.insert("NumPadSeven", Qt::Key_7);
	KeyMap.insert("NumPadEight", Qt::Key_8);
	KeyMap.insert("NumPadNine", Qt::Key_9);

	/* Will be processed as text values (see below)
	KeyMap.insert("Multiply", Qt::Key_multiply);
	KeyMap.insert("Add", Qt::Key_Plus);
	KeyMap.insert("Subtract", Qt::Key_Minus);
	KeyMap.insert("Decimal", Qt::Key_Percent);
	KeyMap.insert("Divide", Qt::Key_division);*/

	KeyMap.insert("F1", Qt::Key_F1);
	KeyMap.insert("F2", Qt::Key_F2);
	KeyMap.insert("F3", Qt::Key_F3);
	KeyMap.insert("F4", Qt::Key_F4);
	KeyMap.insert("F5", Qt::Key_F5);
	KeyMap.insert("F6", Qt::Key_F6);
	KeyMap.insert("F7", Qt::Key_F7);
	KeyMap.insert("F8", Qt::Key_F8);
	KeyMap.insert("F9", Qt::Key_F9);
	KeyMap.insert("F10", Qt::Key_F10);
	KeyMap.insert("F11", Qt::Key_F11);
	KeyMap.insert("F12", Qt::Key_F12);

	KeyMap.insert("NumLock", Qt::Key_NumLock);
	KeyMap.insert("ScrollLock", Qt::Key_ScrollLock);

	KeyMap.insert("LeftShift", Qt::Key_Shift);
	KeyMap.insert("RightShift", Qt::Key_Shift);
	KeyMap.insert("LeftControl", Qt::Key_Control);
	KeyMap.insert("RightControl", Qt::Key_Control);
	KeyMap.insert("LeftAlt", Qt::Key_Alt);
	KeyMap.insert("RightAlt", Qt::Key_Alt);
	KeyMap.insert("LeftCommand", Qt::Key_Meta);
	KeyMap.insert("RightCommand", Qt::Key_Meta);

	/* Will be processed as text values (see below)
	KeyMap.insert("Semicolon", Qt::Key_Semicolon);
	KeyMap.insert("Equals", Qt::Key_Equal);
	KeyMap.insert("Comma", Qt::Key_Comma);
	KeyMap.insert("Underscore", Qt::Key_Underscore);
	KeyMap.insert("Period", Qt::Key_Period);
	KeyMap.insert("Slash", Qt::Key_Slash);
	KeyMap.insert("Tilde", Qt::Key_AsciiTilde);
	KeyMap.insert("LeftBracket", Qt::Key_BracketLeft);
	KeyMap.insert("Backslash", Qt::Key_Backslash);
	KeyMap.insert("RightBracket", Qt::Key_BracketRight);
	KeyMap.insert("Quote", Qt::Key_QuoteDbl);*/

	//--------------------------------------------------------------
	KeyTextMap.clear();

	KeyTextMap.insert("Zero", "0");
	KeyTextMap.insert("One", "1");
	KeyTextMap.insert("Two", "2");
	KeyTextMap.insert("Three", "3");
	KeyTextMap.insert("Four", "4");
	KeyTextMap.insert("Five", "5");
	KeyTextMap.insert("Six", "6");
	KeyTextMap.insert("Seven", "7");
	KeyTextMap.insert("Eight", "8");
	KeyTextMap.insert("Nine", "9");

	KeyTextMap.insert("NumPadZero", "0");
	KeyTextMap.insert("NumPadOne", "1");
	KeyTextMap.insert("NumPadTwo", "2");
	KeyTextMap.insert("NumPadThree", "3");
	KeyTextMap.insert("NumPadFour", "4");
	KeyTextMap.insert("NumPadFive", "5");
	KeyTextMap.insert("NumPadSix", "6");
	KeyTextMap.insert("NumPadSeven", "7");
	KeyTextMap.insert("NumPadEight", "8");
	KeyTextMap.insert("NumPadNine", "9");

	KeyTextMap.insert("Multiply", "*");
	KeyTextMap.insert("Add", "+");
	KeyTextMap.insert("Subtract", "-");
	KeyTextMap.insert("Decimal", "%");
	KeyTextMap.insert("Divide", "/");

	KeyTextMap.insert("Semicolon", ";");
	KeyTextMap.insert("Equals", "=");
	KeyTextMap.insert("Comma", ",");
	KeyTextMap.insert("Underscore", "_");
	KeyTextMap.insert("Period", ".");
	KeyTextMap.insert("Slash", "/");
	KeyTextMap.insert("Tilde", "`");
	KeyTextMap.insert("LeftBracket", "[");
	KeyTextMap.insert("Backslash", "\\");
	KeyTextMap.insert("RightBracket", "]");
	KeyTextMap.insert("Quote", "'");

	//--------------------------------------------------------------
	KeyShiftMap.clear();

	KeyShiftMap.insert("0", ")");
	KeyShiftMap.insert("1", "!");
	KeyShiftMap.insert("2", "@");
	KeyShiftMap.insert("3", "#");
	KeyShiftMap.insert("4", "$");
	KeyShiftMap.insert("5", "%");
	KeyShiftMap.insert("6", "^");
	KeyShiftMap.insert("7", "&");
	KeyShiftMap.insert("8", "*");
	KeyShiftMap.insert("9", "(");

	KeyShiftMap.insert(";", ":");
	KeyShiftMap.insert("=", "+");
	KeyShiftMap.insert(".", ">");
	KeyShiftMap.insert("-", "_");
	KeyShiftMap.insert(",", "<");
	KeyShiftMap.insert("/", "?");
	KeyShiftMap.insert("`", "~");
	KeyShiftMap.insert("[", "{");
	KeyShiftMap.insert("\\", "|");
	KeyShiftMap.insert("]", "}");
	KeyShiftMap.insert("'", "\"");
}

//////////////////////////////////////////////////////////////////////////
// WebPage class

VaQuoleWebUI::VaQuoleWebUI()
{
	ExtComm = new UIDataKeeper;
}

void VaQuoleWebUI::Destroy()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->bMarkedForDelete = true;
}

UIDataKeeper* VaQuoleWebUI::GetData()
{
	Q_CHECK_PTR(ExtComm);
	return ExtComm;
}

/** Register UI page in global UI manager */
void VaQuoleWebUI::Register()
{
	Q_CHECK_PTR(pAppThread);

	pAppThread->AddPage(this);
}

void VaQuoleWebUI::OpenURL(const TCHAR* NewURL)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->NewURL = QString::fromUtf16((const ushort*)NewURL);
}

void VaQuoleWebUI::OpenBenchmark()
{
	OpenURL(L"http://www.smashcat.org/av/canvas_test/");
}

void VaQuoleWebUI::EvaluateJavaScript(const TCHAR *ScriptSource)
{
	return;
	Q_CHECK_PTR(ExtComm);

	//QString Str = QString::fromUtf16((const ushort*)ScriptSource);
	//WebView->page()->mainFrame()->evaluateJavaScript(Str);
}

const uchar * VaQuoleWebUI::GrabView()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	return ExtComm->ImageBits;
}

void VaQuoleWebUI::SetTransparent(bool Transparent)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->bDesiredTransparency = Transparent;
}

void VaQuoleWebUI::Resize(int w, int h)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->DesiredWidth = w;
	ExtComm->DesiredHeight = h;
}

bool VaQuoleWebUI::IsPendingVisualEvents()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	bool bPendingTransparency = ExtComm->bTransparent != ExtComm->bDesiredTransparency;
	bool bPendingSize = (ExtComm->Width != ExtComm->DesiredWidth) || (ExtComm->Height != ExtComm->DesiredHeight);

	return (bPendingTransparency || bPendingSize);
}

//////////////////////////////////////////////////////////////////////////
// JS commands callback

int VaQuoleWebUI::GetCachedCommandsNumber()
{
	return 0;
	Q_CHECK_PTR(ExtComm);

	//return WebView->getCachedCommandsNumber();
}

TCHAR * VaQuoleWebUI::GetCachedCommand(int Index)
{
	return NULL;
	Q_CHECK_PTR(ExtComm);

	//return (TCHAR *)WebView->getCachedCommand(Index).utf16();
}

void VaQuoleWebUI::ClearCachedCommands()
{
	return;
	Q_CHECK_PTR(ExtComm);

	//WebView->clearCachedCommands();
}

//////////////////////////////////////////////////////////////////////////
// Player input

void VaQuoleWebUI::InputMouse(int X, int Y, VaQuole::EMouseButton::Type Button,
								bool bMouseDown,
								const VaQuole::KeyModifiers Modifiers)
{
	std::lock_guard<std::mutex> guard(mutex);

	MouseEvent Event;
	Event.eventPos = QPoint(X,Y);
	Event.bButtonPressed = bMouseDown;

	// Prepare modifiers
	Modifiers.bAltDown == true ? Event.modifiers |= Qt::AltModifier : 0;
	Modifiers.bCtrlDown == true ? Event.modifiers |= Qt::ControlModifier : 0;
	Modifiers.bShiftDown == true ? Event.modifiers |= Qt::ShiftModifier : 0;

	// Convert button from UE4 to Qt enum value
	switch (Button)
	{
	case VaQuole::EMouseButton::NoButton:
		Event.button = Qt::NoButton;
		break;

	case VaQuole::EMouseButton::LeftButton:
		Event.button = Qt::LeftButton;
		break;

	case VaQuole::EMouseButton::RightButton:
		Event.button = Qt::RightButton;
		break;

	case VaQuole::EMouseButton::MiddleButton:
		Event.button = Qt::MiddleButton;
		break;

	case VaQuole::EMouseButton::XButton1:
		Event.button = Qt::XButton1;
		break;

	case VaQuole::EMouseButton::XButton2:
		Event.button = Qt::XButton2;
		break;

	case VaQuole::EMouseButton::ScrollUp:
		break;

	case VaQuole::EMouseButton::ScrollDown:
		break;

	default:
		Event.button = Qt::NoButton;
		break;
	}

	Q_CHECK_PTR(ExtComm);
	ExtComm->MouseEvents.append(Event);
}

void VaQuoleWebUI::InputKey(const TCHAR *Key,
							const unsigned int KeyCode,
							const bool bPressed,
							const VaQuole::KeyModifiers Modifiers)
{
	std::lock_guard<std::mutex> guard(mutex);

	KeyEvent Event;
	Event.bKeyPressed = bPressed;

	// Prepare modifiers
	Modifiers.bAltDown == true ? Event.modifiers |= Qt::AltModifier : 0;
	Modifiers.bCtrlDown == true ? Event.modifiers |= Qt::ControlModifier : 0;
	Modifiers.bShiftDown == true ? Event.modifiers |= Qt::ShiftModifier : 0;

	// Prepare key
	QString KeyStr = QString::fromUtf16((const ushort*)Key);
	Event.key = KeyMap.value(KeyStr, Qt::Key_unknown);
	Event.text = KeyTextMap.value(KeyStr);

	// Give a chance for UE4 to determine the character
	if(Event.key == Qt::Key_unknown && KeyCode != -1)
	{
		Event.key = (Qt::Key)KeyCode;
	}

	// [1] Qt bug temporary solution
	// https://bugreports.qt-project.org/browse/QTBUG-40100
	if(Event.text.isEmpty())
	{
		Event.text = QString(QChar(Event.key));
	}

	// [2] Qt bug temporary solution
	// Apply shift modificator
	if( Modifiers.bShiftDown )
	{
		QString ShiftedStr = KeyShiftMap.value(Event.text);
		if(!ShiftedStr.isNull())
		{
			Event.text = ShiftedStr;
		}
	}
	else
	{
		Event.text = Event.text.toLower();
	}

	// Apply keypad modifier for numpad data
	if (KeyStr.contains("NumPad", Qt::CaseInsensitive))
	{
		Event.modifiers |= Qt::KeypadModifier;
	}

	Q_CHECK_PTR(ExtComm);
	ExtComm->KeyEvents.append(Event);
}

} // namespace VaQuole
<commit_msg>Compilation warning on QT-40100 bug<commit_after>// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#include "VaQuoleUILib.h"
#include "VaQuoleAppThread.h"

#include <QApplication>
#include <QDebug>

#include <QImage>
#include <QWebFrame>
#include <QString>
#include <QHash>

namespace VaQuole
{

/** Main app thread with QApplication */
static VaQuoleUIManager* pAppThread = NULL;

/** Key map to convert UE4 keys to Qt ones */
QHash<QString, Qt::Key> KeyMap;

/** Key map to convert UE4 keys to QString characters */
QHash<QString, QString> KeyTextMap;

/**
 * Key map to apply SHIFT modificator. Seemed as Qt bug,
 * Check https://bugreports.qt-project.org/browse/QTBUG-40100
 */
QHash<QString, QString> KeyShiftMap;

//////////////////////////////////////////////////////////////////////////
// Common lib functions

void Init()
{
	// Check that we haven't qApp already
	if (QApplication::instance() == nullptr)
	{
		pAppThread = new VaQuoleUIManager();
		pAppThread->start();
	}

	InitKeyMaps();
}

void Cleanup()
{
	qDebug() << "Clean so clean";

	if (pAppThread != NULL)
	{
		pAppThread->~VaQuoleUIManager();//->stop();
	}
}

VaQuoleWebUI* ConstructNewUI()
{
	VaQuoleWebUI* NewUI = new VaQuoleWebUI();
	NewUI->Register();

	return NewUI;
}

void InitKeyMaps()
{
	KeyMap.clear();

	KeyMap.insert("BackSpace", Qt::Key_Backspace);
	KeyMap.insert("Tab", Qt::Key_Tab);
	KeyMap.insert("Enter", Qt::Key_Enter);
	KeyMap.insert("Pause", Qt::Key_Pause);

	KeyMap.insert("CapsLock", Qt::Key_CapsLock);
	KeyMap.insert("Escape", Qt::Key_Escape);
	KeyMap.insert("SpaceBar", Qt::Key_Space);
	KeyMap.insert("PageUp", Qt::Key_PageUp);
	KeyMap.insert("PageDown", Qt::Key_PageDown);
	KeyMap.insert("End", Qt::Key_End);
	KeyMap.insert("Home", Qt::Key_Home);

	KeyMap.insert("Left", Qt::Key_Left);
	KeyMap.insert("Up", Qt::Key_Up);
	KeyMap.insert("Right", Qt::Key_Right);
	KeyMap.insert("Down", Qt::Key_Down);
	KeyMap.insert("Insert", Qt::Key_Insert);
	KeyMap.insert("Delete", Qt::Key_Delete);

	KeyMap.insert("NumPadZero", Qt::Key_0);
	KeyMap.insert("NumPadOne", Qt::Key_1);
	KeyMap.insert("NumPadTwo", Qt::Key_2);
	KeyMap.insert("NumPadThree", Qt::Key_3);
	KeyMap.insert("NumPadFour", Qt::Key_4);
	KeyMap.insert("NumPadFive", Qt::Key_5);
	KeyMap.insert("NumPadSix", Qt::Key_6);
	KeyMap.insert("NumPadSeven", Qt::Key_7);
	KeyMap.insert("NumPadEight", Qt::Key_8);
	KeyMap.insert("NumPadNine", Qt::Key_9);

	/* Will be processed as text values (see below)
	KeyMap.insert("Multiply", Qt::Key_multiply);
	KeyMap.insert("Add", Qt::Key_Plus);
	KeyMap.insert("Subtract", Qt::Key_Minus);
	KeyMap.insert("Decimal", Qt::Key_Percent);
	KeyMap.insert("Divide", Qt::Key_division);*/

	KeyMap.insert("F1", Qt::Key_F1);
	KeyMap.insert("F2", Qt::Key_F2);
	KeyMap.insert("F3", Qt::Key_F3);
	KeyMap.insert("F4", Qt::Key_F4);
	KeyMap.insert("F5", Qt::Key_F5);
	KeyMap.insert("F6", Qt::Key_F6);
	KeyMap.insert("F7", Qt::Key_F7);
	KeyMap.insert("F8", Qt::Key_F8);
	KeyMap.insert("F9", Qt::Key_F9);
	KeyMap.insert("F10", Qt::Key_F10);
	KeyMap.insert("F11", Qt::Key_F11);
	KeyMap.insert("F12", Qt::Key_F12);

	KeyMap.insert("NumLock", Qt::Key_NumLock);
	KeyMap.insert("ScrollLock", Qt::Key_ScrollLock);

	KeyMap.insert("LeftShift", Qt::Key_Shift);
	KeyMap.insert("RightShift", Qt::Key_Shift);
	KeyMap.insert("LeftControl", Qt::Key_Control);
	KeyMap.insert("RightControl", Qt::Key_Control);
	KeyMap.insert("LeftAlt", Qt::Key_Alt);
	KeyMap.insert("RightAlt", Qt::Key_Alt);
	KeyMap.insert("LeftCommand", Qt::Key_Meta);
	KeyMap.insert("RightCommand", Qt::Key_Meta);

	/* Will be processed as text values (see below)
	KeyMap.insert("Semicolon", Qt::Key_Semicolon);
	KeyMap.insert("Equals", Qt::Key_Equal);
	KeyMap.insert("Comma", Qt::Key_Comma);
	KeyMap.insert("Underscore", Qt::Key_Underscore);
	KeyMap.insert("Period", Qt::Key_Period);
	KeyMap.insert("Slash", Qt::Key_Slash);
	KeyMap.insert("Tilde", Qt::Key_AsciiTilde);
	KeyMap.insert("LeftBracket", Qt::Key_BracketLeft);
	KeyMap.insert("Backslash", Qt::Key_Backslash);
	KeyMap.insert("RightBracket", Qt::Key_BracketRight);
	KeyMap.insert("Quote", Qt::Key_QuoteDbl);*/

	//--------------------------------------------------------------
	KeyTextMap.clear();

	KeyTextMap.insert("Zero", "0");
	KeyTextMap.insert("One", "1");
	KeyTextMap.insert("Two", "2");
	KeyTextMap.insert("Three", "3");
	KeyTextMap.insert("Four", "4");
	KeyTextMap.insert("Five", "5");
	KeyTextMap.insert("Six", "6");
	KeyTextMap.insert("Seven", "7");
	KeyTextMap.insert("Eight", "8");
	KeyTextMap.insert("Nine", "9");

	KeyTextMap.insert("NumPadZero", "0");
	KeyTextMap.insert("NumPadOne", "1");
	KeyTextMap.insert("NumPadTwo", "2");
	KeyTextMap.insert("NumPadThree", "3");
	KeyTextMap.insert("NumPadFour", "4");
	KeyTextMap.insert("NumPadFive", "5");
	KeyTextMap.insert("NumPadSix", "6");
	KeyTextMap.insert("NumPadSeven", "7");
	KeyTextMap.insert("NumPadEight", "8");
	KeyTextMap.insert("NumPadNine", "9");

	KeyTextMap.insert("Multiply", "*");
	KeyTextMap.insert("Add", "+");
	KeyTextMap.insert("Subtract", "-");
	KeyTextMap.insert("Decimal", "%");
	KeyTextMap.insert("Divide", "/");

	KeyTextMap.insert("Semicolon", ";");
	KeyTextMap.insert("Equals", "=");
	KeyTextMap.insert("Comma", ",");
	KeyTextMap.insert("Underscore", "_");
	KeyTextMap.insert("Period", ".");
	KeyTextMap.insert("Slash", "/");
	KeyTextMap.insert("Tilde", "`");
	KeyTextMap.insert("LeftBracket", "[");
	KeyTextMap.insert("Backslash", "\\");
	KeyTextMap.insert("RightBracket", "]");
	KeyTextMap.insert("Quote", "'");

	//--------------------------------------------------------------
	KeyShiftMap.clear();

	KeyShiftMap.insert("0", ")");
	KeyShiftMap.insert("1", "!");
	KeyShiftMap.insert("2", "@");
	KeyShiftMap.insert("3", "#");
	KeyShiftMap.insert("4", "$");
	KeyShiftMap.insert("5", "%");
	KeyShiftMap.insert("6", "^");
	KeyShiftMap.insert("7", "&");
	KeyShiftMap.insert("8", "*");
	KeyShiftMap.insert("9", "(");

	KeyShiftMap.insert(";", ":");
	KeyShiftMap.insert("=", "+");
	KeyShiftMap.insert(".", ">");
	KeyShiftMap.insert("-", "_");
	KeyShiftMap.insert(",", "<");
	KeyShiftMap.insert("/", "?");
	KeyShiftMap.insert("`", "~");
	KeyShiftMap.insert("[", "{");
	KeyShiftMap.insert("\\", "|");
	KeyShiftMap.insert("]", "}");
	KeyShiftMap.insert("'", "\"");
}

//////////////////////////////////////////////////////////////////////////
// WebPage class

VaQuoleWebUI::VaQuoleWebUI()
{
	ExtComm = new UIDataKeeper;
}

void VaQuoleWebUI::Destroy()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->bMarkedForDelete = true;
}

UIDataKeeper* VaQuoleWebUI::GetData()
{
	Q_CHECK_PTR(ExtComm);
	return ExtComm;
}

/** Register UI page in global UI manager */
void VaQuoleWebUI::Register()
{
	Q_CHECK_PTR(pAppThread);

	pAppThread->AddPage(this);
}

void VaQuoleWebUI::OpenURL(const TCHAR* NewURL)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->NewURL = QString::fromUtf16((const ushort*)NewURL);
}

void VaQuoleWebUI::OpenBenchmark()
{
	OpenURL(L"http://www.smashcat.org/av/canvas_test/");
}

void VaQuoleWebUI::EvaluateJavaScript(const TCHAR *ScriptSource)
{
	return;
	Q_CHECK_PTR(ExtComm);

	//QString Str = QString::fromUtf16((const ushort*)ScriptSource);
	//WebView->page()->mainFrame()->evaluateJavaScript(Str);
}

const uchar * VaQuoleWebUI::GrabView()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	return ExtComm->ImageBits;
}

void VaQuoleWebUI::SetTransparent(bool Transparent)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->bDesiredTransparency = Transparent;
}

void VaQuoleWebUI::Resize(int w, int h)
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	ExtComm->DesiredWidth = w;
	ExtComm->DesiredHeight = h;
}

bool VaQuoleWebUI::IsPendingVisualEvents()
{
	std::lock_guard<std::mutex> guard(mutex);

	Q_CHECK_PTR(ExtComm);
	bool bPendingTransparency = ExtComm->bTransparent != ExtComm->bDesiredTransparency;
	bool bPendingSize = (ExtComm->Width != ExtComm->DesiredWidth) || (ExtComm->Height != ExtComm->DesiredHeight);

	return (bPendingTransparency || bPendingSize);
}

//////////////////////////////////////////////////////////////////////////
// JS commands callback

int VaQuoleWebUI::GetCachedCommandsNumber()
{
	return 0;
	Q_CHECK_PTR(ExtComm);

	//return WebView->getCachedCommandsNumber();
}

TCHAR * VaQuoleWebUI::GetCachedCommand(int Index)
{
	return NULL;
	Q_CHECK_PTR(ExtComm);

	//return (TCHAR *)WebView->getCachedCommand(Index).utf16();
}

void VaQuoleWebUI::ClearCachedCommands()
{
	return;
	Q_CHECK_PTR(ExtComm);

	//WebView->clearCachedCommands();
}

//////////////////////////////////////////////////////////////////////////
// Player input

void VaQuoleWebUI::InputMouse(int X, int Y, VaQuole::EMouseButton::Type Button,
								bool bMouseDown,
								const VaQuole::KeyModifiers Modifiers)
{
	std::lock_guard<std::mutex> guard(mutex);

	MouseEvent Event;
	Event.eventPos = QPoint(X,Y);
	Event.bButtonPressed = bMouseDown;

	// Prepare modifiers
	Modifiers.bAltDown == true ? Event.modifiers |= Qt::AltModifier : 0;
	Modifiers.bCtrlDown == true ? Event.modifiers |= Qt::ControlModifier : 0;
	Modifiers.bShiftDown == true ? Event.modifiers |= Qt::ShiftModifier : 0;

	// Convert button from UE4 to Qt enum value
	switch (Button)
	{
	case VaQuole::EMouseButton::NoButton:
		Event.button = Qt::NoButton;
		break;

	case VaQuole::EMouseButton::LeftButton:
		Event.button = Qt::LeftButton;
		break;

	case VaQuole::EMouseButton::RightButton:
		Event.button = Qt::RightButton;
		break;

	case VaQuole::EMouseButton::MiddleButton:
		Event.button = Qt::MiddleButton;
		break;

	case VaQuole::EMouseButton::XButton1:
		Event.button = Qt::XButton1;
		break;

	case VaQuole::EMouseButton::XButton2:
		Event.button = Qt::XButton2;
		break;

	case VaQuole::EMouseButton::ScrollUp:
		break;

	case VaQuole::EMouseButton::ScrollDown:
		break;

	default:
		Event.button = Qt::NoButton;
		break;
	}

	Q_CHECK_PTR(ExtComm);
	ExtComm->MouseEvents.append(Event);
}

void VaQuoleWebUI::InputKey(const TCHAR *Key,
							const unsigned int KeyCode,
							const bool bPressed,
							const VaQuole::KeyModifiers Modifiers)
{
	std::lock_guard<std::mutex> guard(mutex);

	KeyEvent Event;
	Event.bKeyPressed = bPressed;

	// Prepare modifiers
	Modifiers.bAltDown == true ? Event.modifiers |= Qt::AltModifier : 0;
	Modifiers.bCtrlDown == true ? Event.modifiers |= Qt::ControlModifier : 0;
	Modifiers.bShiftDown == true ? Event.modifiers |= Qt::ShiftModifier : 0;

	// Prepare key
	QString KeyStr = QString::fromUtf16((const ushort*)Key);
	Event.key = KeyMap.value(KeyStr, Qt::Key_unknown);
	Event.text = KeyTextMap.value(KeyStr);

	// Give a chance for UE4 to determine the character
	if(Event.key == Qt::Key_unknown && KeyCode != -1)
	{
		Event.key = (Qt::Key)KeyCode;
	}

#pragma message ("@FIXME QT-40100 bug temporary solution")

	// [1] Qt bug temporary solution
	// https://bugreports.qt-project.org/browse/QTBUG-40100
	if(Event.text.isEmpty())
	{
		Event.text = QString(QChar(Event.key));
	}

	// [2] Qt bug temporary solution
	// Apply shift modificator
	if( Modifiers.bShiftDown )
	{
		QString ShiftedStr = KeyShiftMap.value(Event.text);
		if(!ShiftedStr.isNull())
		{
			Event.text = ShiftedStr;
		}
	}
	else
	{
		Event.text = Event.text.toLower();
	}

	// Apply keypad modifier for numpad data
	if (KeyStr.contains("NumPad", Qt::CaseInsensitive))
	{
		Event.modifiers |= Qt::KeypadModifier;
	}

	Q_CHECK_PTR(ExtComm);
	ExtComm->KeyEvents.append(Event);
}

} // namespace VaQuole
<|endoftext|>


<commit_before>// Copyright 2016 Benjamin Glatzel
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Precompiled header file
#include "stdafx.h"

namespace Intrinsic
{
namespace Core
{
namespace Settings
{
// Static members
_INTR_STRING Manager::_initialWorld = "Default.world.json";
_INTR_STRING Manager::_assetMeshPath =
    "../../Intrinsic_Assets/app/assets/meshes";
_INTR_STRING Manager::_assetTexturePath =
    "../../Intrinsic_Assets/app/assets/textures";
uint32_t Manager::_rendererFlags = 0u;
float Manager::_targetFrameRate = 0.016f;
WindowMode::Enum Manager::_windowMode = WindowMode::kWindowed;
uint32_t Manager::_screenResolutionWidth = 1280u;
uint32_t Manager::_screenResolutionHeight = 720u;

namespace
{
template <typename T>
_INTR_INLINE void readSetting(rapidjson::Document& p_Doc, const Name& p_Name,
                              T& p_Target)
{
  if (p_Doc.HasMember(p_Name._string.c_str()))
  {
    p_Target = p_Doc[p_Name._string.c_str()].Get<T>();
    _INTR_LOG_INFO("%s = '%s'", p_Name._string.c_str(),
                   StringUtil::toString(p_Target).c_str());
  }
}

template <>
_INTR_INLINE void readSetting(rapidjson::Document& p_Doc, const Name& p_Name,
                              _INTR_STRING& p_Target)
{
  if (p_Doc.HasMember(p_Name._string.c_str()))
  {
    p_Target = p_Doc[p_Name._string.c_str()].GetString();
    _INTR_LOG_INFO("%s = '%s'", p_Name._string.c_str(),
                   StringUtil::toString(p_Target).c_str());
  }
}
}

// <-

void Manager::loadSettings()
{
  FILE* fp = fopen("settings.json", "rb");

  if (fp == nullptr)
  {
    _INTR_LOG_WARNING("No settings file available - using default values...");
    return;
  }

  _INTR_LOG_INFO("Reading settings file...");
  _INTR_LOG_PUSH();

  rapidjson::Document doc;

  char* readBuffer = (char*)Tlsf::MainAllocator::allocate(65536u);
  {
    rapidjson::FileReadStream is(fp, readBuffer, 65536u);
    doc.ParseStream(is);
    fclose(fp);
  }
  Tlsf::MainAllocator::free(readBuffer);

  {
    bool rendererValidationEnabled =
        (_rendererFlags & RendererFlags::kValidationEnabled) > 0u;
    readSetting(doc, _N(rendererValidationEnabled), rendererValidationEnabled);
    if (rendererValidationEnabled)
      _rendererFlags |= RendererFlags::kValidationEnabled;
    else
      _rendererFlags &= ~RendererFlags::kValidationEnabled;

    readSetting(doc, _N(targetFrameRate), _targetFrameRate);
    readSetting(doc, _N(windowMode), (uint32_t&)_windowMode);
    readSetting(doc, _N(screenResolutionWidth), _screenResolutionWidth);
    readSetting(doc, _N(screenResolutionHeight), _screenResolutionHeight);
    readSetting(doc, _N(initialWorld), _initialWorld);
    readSetting(doc, _N(assetMeshPath), _assetMeshPath);
    readSetting(doc, _N(assetTexturePath), _assetTexturePath);
  }

  _INTR_LOG_POP();
}
}
}
}
<commit_msg>Unnecessary "toString" call<commit_after>// Copyright 2016 Benjamin Glatzel
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Precompiled header file
#include "stdafx.h"

namespace Intrinsic
{
namespace Core
{
namespace Settings
{
// Static members
_INTR_STRING Manager::_initialWorld = "Default.world.json";
_INTR_STRING Manager::_assetMeshPath =
    "../../Intrinsic_Assets/app/assets/meshes";
_INTR_STRING Manager::_assetTexturePath =
    "../../Intrinsic_Assets/app/assets/textures";
uint32_t Manager::_rendererFlags = 0u;
float Manager::_targetFrameRate = 0.016f;
WindowMode::Enum Manager::_windowMode = WindowMode::kWindowed;
uint32_t Manager::_screenResolutionWidth = 1280u;
uint32_t Manager::_screenResolutionHeight = 720u;

namespace
{
template <typename T>
_INTR_INLINE void readSetting(rapidjson::Document& p_Doc, const Name& p_Name,
                              T& p_Target)
{
  if (p_Doc.HasMember(p_Name._string.c_str()))
  {
    p_Target = p_Doc[p_Name._string.c_str()].Get<T>();
    _INTR_LOG_INFO("%s = '%s'", p_Name._string.c_str(),
                   StringUtil::toString(p_Target).c_str());
  }
}

template <>
_INTR_INLINE void readSetting(rapidjson::Document& p_Doc, const Name& p_Name,
                              _INTR_STRING& p_Target)
{
  if (p_Doc.HasMember(p_Name._string.c_str()))
  {
    p_Target = p_Doc[p_Name._string.c_str()].GetString();
    _INTR_LOG_INFO("%s = '%s'", p_Name._string.c_str(), p_Target.c_str());
  }
}
}

// <-

void Manager::loadSettings()
{
  FILE* fp = fopen("settings.json", "rb");

  if (fp == nullptr)
  {
    _INTR_LOG_WARNING("No settings file available - using default values...");
    return;
  }

  _INTR_LOG_INFO("Reading settings file...");
  _INTR_LOG_PUSH();

  rapidjson::Document doc;

  char* readBuffer = (char*)Tlsf::MainAllocator::allocate(65536u);
  {
    rapidjson::FileReadStream is(fp, readBuffer, 65536u);
    doc.ParseStream(is);
    fclose(fp);
  }
  Tlsf::MainAllocator::free(readBuffer);

  {
    bool rendererValidationEnabled =
        (_rendererFlags & RendererFlags::kValidationEnabled) > 0u;
    readSetting(doc, _N(rendererValidationEnabled), rendererValidationEnabled);
    if (rendererValidationEnabled)
      _rendererFlags |= RendererFlags::kValidationEnabled;
    else
      _rendererFlags &= ~RendererFlags::kValidationEnabled;

    readSetting(doc, _N(targetFrameRate), _targetFrameRate);
    readSetting(doc, _N(windowMode), (uint32_t&)_windowMode);
    readSetting(doc, _N(screenResolutionWidth), _screenResolutionWidth);
    readSetting(doc, _N(screenResolutionHeight), _screenResolutionHeight);
    readSetting(doc, _N(initialWorld), _initialWorld);
    readSetting(doc, _N(assetMeshPath), _assetMeshPath);
    readSetting(doc, _N(assetTexturePath), _assetTexturePath);
  }

  _INTR_LOG_POP();
}
}
}
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2017 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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

#include "libmesh/boundary_volume_solution_transfer.h"
#include "libmesh/elem.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/dof_map.h"

namespace libMesh {

void BoundaryVolumeSolutionTransfer::transfer(const Variable & from_var,
                                              const Variable & to_var)
{
  // Determine which direction the transfer is in
  System * from_sys = from_var.system();
  System * to_sys = to_var.system();

  unsigned int
    from_dimension = from_sys->get_mesh().mesh_dimension(),
    to_dimension = to_sys->get_mesh().mesh_dimension();

  // Sanity check
  if (from_dimension == to_dimension)
    libmesh_error_msg("Error: Transfer must be from volume mesh to its boundary or vice-versa!");

  if (from_dimension > to_dimension)
    this->transfer_volume_boundary(from_var, to_var);
  else
    this->transfer_boundary_volume(from_var, to_var);
}

void BoundaryVolumeSolutionTransfer::
transfer_volume_boundary(const Variable & from_var, const Variable & to_var)
{
  // Get references to the Systems from the Variables
  System * from_sys = from_var.system(); // volume system
  System * to_sys = to_var.system();     // boundary system

  // Get reference to the BoundaryMesh.  Note: we always loop over the
  // BoundaryMesh since, by definition, it has fewer dofs than the
  // volume mesh.
  const MeshBase & to_mesh = to_sys->get_mesh();

  // Get system number and variable numbers
  const unsigned short int from_sys_number = from_sys->number();
  const unsigned short int from_var_number = from_var.number();

  const unsigned short int to_sys_number = to_sys->number();
  const unsigned short int to_var_number = to_var.number();

  // Get a constant reference to variables, get their number of components
  const unsigned short int from_n_comp = from_var.n_components();
  const unsigned short int to_n_comp = to_var.n_components();

  // Sanity check that the variables have the same number of components
  libmesh_assert_equal_to(from_n_comp, to_n_comp);

  // Iterator for BoundaryMesh.
  MeshBase::const_element_iterator       el     = to_mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el = to_mesh.active_local_elements_end();

  // Construct map from "from" dofs to "to" dofs.
  typedef std::map<numeric_index_type, numeric_index_type> DofMapping;
  DofMapping dof_mapping;

  // Loop through all boundary elements.
  for ( ; el != end_el; ++el)
    {
      const Elem * to_elem = *el;
      const Elem * from_elem = to_elem->interior_parent();

      if (!from_elem)
        libmesh_error_msg("Error, transfer must be between a Mesh and its associated BoundaryMesh.");

      // loop through all nodes in each boundary element.
      for (unsigned int node=0; node < to_elem->n_nodes(); node++)
        {
          // Node in boundary element.
          const Node * to_node = to_elem->node_ptr(node);

          for (unsigned int node_id=0; node_id < from_elem->n_nodes(); node_id++)
            {
              // Nodes in interior_parent element.
              const Node * from_node = from_elem->node_ptr(node_id);

              const dof_id_type from_dof = from_node->dof_number(from_sys_number,
                                                                 from_var_number,
                                                                 from_n_comp - 1);

              // See if we've already encountered this DOF in the loop
              // over boundary elements.
              DofMapping::iterator it = dof_mapping.find(from_dof);

              // If we've already mapped this dof, we don't need to map
              // it again or do floating point comparisons.
              if (it == dof_mapping.end() &&
                  from_node->absolute_fuzzy_equals(*to_node, TOLERANCE))
                {
                  // Global dof_index for node in BoundaryMesh.
                  const dof_id_type to_dof = to_node->dof_number(to_sys_number,
                                                                 to_var_number,
                                                                 to_n_comp - 1);

                  // Keep track of the volume system dof index which is needed.
                  dof_mapping[from_dof] = to_dof;
                }
            }
        }
    }

  // Construct a vector of the indices needed from the Volume system's
  // global solution vector on this processor.
  std::vector<numeric_index_type> needed_indices;
  needed_indices.reserve(dof_mapping.size());
  {
    DofMapping::iterator
      it = dof_mapping.begin(),
      end = dof_mapping.end();

    for (; it!=end; ++it)
      needed_indices.push_back(it->first);
  }

  // Communicate just the required values without making a copy of the
  // global solution vector.
  std::vector<Number> needed_values;
  from_sys->solution->localize(needed_values, needed_indices);

  // Loop over DofMapping again, assigning values in the
  // Boundary System solution vector.
  {
    DofMapping::iterator
      it = dof_mapping.begin(),
      end = dof_mapping.end();

    for (unsigned idx=0; it!=end; ++it, ++idx)
      to_sys->solution->set(it->second, needed_values[idx]);
  }
}

void BoundaryVolumeSolutionTransfer::
transfer_boundary_volume(const Variable & from_var, const Variable & to_var)
{
  // Get references to the Systems from the Variables
  System * from_sys = from_var.system(); // boundary system
  System * to_sys = to_var.system();     // volume system

  // Get reference to BoundaryMesh.
  const MeshBase & from_mesh = from_sys->get_mesh();

  // DofMap for BoundaryMesh
  const DofMap & dof_map = from_sys->get_dof_map();

  // Get system number and variable numbers
  const unsigned short int to_sys_number = to_sys->number();
  const unsigned short int to_var_number = to_var.number();
  const unsigned short int from_var_number = from_var.number();
  const unsigned short int to_n_comp = to_var.n_components();

  // Iterator for BoundaryMesh.
  MeshBase::const_element_iterator       el     = from_mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el = from_mesh.active_local_elements_end();

  // In order to get solution vectors from BoundaryMesh
  std::vector<dof_id_type> from_dof_indices;
  std::vector<Number> value;

  // Loop through all boundary elements.
  for (; el != end_el; ++el)
    {
      const Elem * from_elem = *el;
      const Elem * to_elem = from_elem->interior_parent();

      if (!to_elem)
        libmesh_error_msg("Error, transfer must be between a Mesh and its associated BoundaryMesh.");

      // Get dof indices for phi2 for all nodes on this boundary element
      dof_map.dof_indices(from_elem, from_dof_indices, from_var_number);

      // Get values from BoundaryMesh for this element
      from_sys->current_local_solution->get(from_dof_indices, value);

      // loop through all nodes in each boundary element.
      for (unsigned int node=0; node < from_elem->n_nodes(); node++)
        {
          // Node in boundary element.
          const Node * from_node = from_elem->node_ptr(node);

          for (unsigned int node_id=0; node_id < to_elem->n_nodes(); node_id++)
            {
              // Nodes in interior_parent element.
              const Node * to_node = to_elem->node_ptr(node_id);

              // Match BoundaryNode & VolumeNode.
              if (to_node->absolute_fuzzy_equals(*from_node, TOLERANCE))
                {
                  // Global dof_index for node in VolumeMesh.
                  const dof_id_type to_dof = to_node->dof_number(to_sys_number,
                                                                 to_var_number,
                                                                 to_n_comp - 1);

                  // Assign values to boundary in VolumeMesh.
                  to_sys->solution->set(to_dof, value[node]);
                }
            }
        }
    }
}

} // namespace libMesh
<commit_msg>Use rangefor in BoundaryVolumeSolutionTransfer::transfer_volume_boundary().<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2017 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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

#include "libmesh/boundary_volume_solution_transfer.h"
#include "libmesh/elem.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/dof_map.h"

namespace libMesh {

void BoundaryVolumeSolutionTransfer::transfer(const Variable & from_var,
                                              const Variable & to_var)
{
  // Determine which direction the transfer is in
  System * from_sys = from_var.system();
  System * to_sys = to_var.system();

  unsigned int
    from_dimension = from_sys->get_mesh().mesh_dimension(),
    to_dimension = to_sys->get_mesh().mesh_dimension();

  // Sanity check
  if (from_dimension == to_dimension)
    libmesh_error_msg("Error: Transfer must be from volume mesh to its boundary or vice-versa!");

  if (from_dimension > to_dimension)
    this->transfer_volume_boundary(from_var, to_var);
  else
    this->transfer_boundary_volume(from_var, to_var);
}

void BoundaryVolumeSolutionTransfer::
transfer_volume_boundary(const Variable & from_var, const Variable & to_var)
{
  // Get references to the Systems from the Variables
  System * from_sys = from_var.system(); // volume system
  System * to_sys = to_var.system();     // boundary system

  // Get reference to the BoundaryMesh.  Note: we always loop over the
  // BoundaryMesh since, by definition, it has fewer dofs than the
  // volume mesh.
  const MeshBase & to_mesh = to_sys->get_mesh();

  // Get system number and variable numbers
  const unsigned short int from_sys_number = from_sys->number();
  const unsigned short int from_var_number = from_var.number();

  const unsigned short int to_sys_number = to_sys->number();
  const unsigned short int to_var_number = to_var.number();

  // Get a constant reference to variables, get their number of components
  const unsigned short int from_n_comp = from_var.n_components();
  const unsigned short int to_n_comp = to_var.n_components();

  // Sanity check that the variables have the same number of components
  libmesh_assert_equal_to(from_n_comp, to_n_comp);

  // Construct map from "from" dofs to "to" dofs.
  typedef std::map<numeric_index_type, numeric_index_type> DofMapping;
  DofMapping dof_mapping;

  // Loop through all boundary elements.
  for (const auto & to_elem : to_mesh.active_local_element_ptr_range())
    {
      const Elem * from_elem = to_elem->interior_parent();

      if (!from_elem)
        libmesh_error_msg("Error, transfer must be between a Mesh and its associated BoundaryMesh.");

      // loop through all nodes in each boundary element.
      for (unsigned int node=0; node < to_elem->n_nodes(); node++)
        {
          // Node in boundary element.
          const Node * to_node = to_elem->node_ptr(node);

          for (unsigned int node_id=0; node_id < from_elem->n_nodes(); node_id++)
            {
              // Nodes in interior_parent element.
              const Node * from_node = from_elem->node_ptr(node_id);

              const dof_id_type from_dof = from_node->dof_number(from_sys_number,
                                                                 from_var_number,
                                                                 from_n_comp - 1);

              // See if we've already encountered this DOF in the loop
              // over boundary elements.
              DofMapping::iterator it = dof_mapping.find(from_dof);

              // If we've already mapped this dof, we don't need to map
              // it again or do floating point comparisons.
              if (it == dof_mapping.end() &&
                  from_node->absolute_fuzzy_equals(*to_node, TOLERANCE))
                {
                  // Global dof_index for node in BoundaryMesh.
                  const dof_id_type to_dof = to_node->dof_number(to_sys_number,
                                                                 to_var_number,
                                                                 to_n_comp - 1);

                  // Keep track of the volume system dof index which is needed.
                  dof_mapping[from_dof] = to_dof;
                }
            }
        }
    }

  // Construct a vector of the indices needed from the Volume system's
  // global solution vector on this processor.
  std::vector<numeric_index_type> needed_indices;
  needed_indices.reserve(dof_mapping.size());
  {
    DofMapping::iterator
      it = dof_mapping.begin(),
      end = dof_mapping.end();

    for (; it!=end; ++it)
      needed_indices.push_back(it->first);
  }

  // Communicate just the required values without making a copy of the
  // global solution vector.
  std::vector<Number> needed_values;
  from_sys->solution->localize(needed_values, needed_indices);

  // Loop over DofMapping again, assigning values in the
  // Boundary System solution vector.
  {
    DofMapping::iterator
      it = dof_mapping.begin(),
      end = dof_mapping.end();

    for (unsigned idx=0; it!=end; ++it, ++idx)
      to_sys->solution->set(it->second, needed_values[idx]);
  }
}

void BoundaryVolumeSolutionTransfer::
transfer_boundary_volume(const Variable & from_var, const Variable & to_var)
{
  // Get references to the Systems from the Variables
  System * from_sys = from_var.system(); // boundary system
  System * to_sys = to_var.system();     // volume system

  // Get reference to BoundaryMesh.
  const MeshBase & from_mesh = from_sys->get_mesh();

  // DofMap for BoundaryMesh
  const DofMap & dof_map = from_sys->get_dof_map();

  // Get system number and variable numbers
  const unsigned short int to_sys_number = to_sys->number();
  const unsigned short int to_var_number = to_var.number();
  const unsigned short int from_var_number = from_var.number();
  const unsigned short int to_n_comp = to_var.n_components();

  // Iterator for BoundaryMesh.
  MeshBase::const_element_iterator       el     = from_mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el = from_mesh.active_local_elements_end();

  // In order to get solution vectors from BoundaryMesh
  std::vector<dof_id_type> from_dof_indices;
  std::vector<Number> value;

  // Loop through all boundary elements.
  for (; el != end_el; ++el)
    {
      const Elem * from_elem = *el;
      const Elem * to_elem = from_elem->interior_parent();

      if (!to_elem)
        libmesh_error_msg("Error, transfer must be between a Mesh and its associated BoundaryMesh.");

      // Get dof indices for phi2 for all nodes on this boundary element
      dof_map.dof_indices(from_elem, from_dof_indices, from_var_number);

      // Get values from BoundaryMesh for this element
      from_sys->current_local_solution->get(from_dof_indices, value);

      // loop through all nodes in each boundary element.
      for (unsigned int node=0; node < from_elem->n_nodes(); node++)
        {
          // Node in boundary element.
          const Node * from_node = from_elem->node_ptr(node);

          for (unsigned int node_id=0; node_id < to_elem->n_nodes(); node_id++)
            {
              // Nodes in interior_parent element.
              const Node * to_node = to_elem->node_ptr(node_id);

              // Match BoundaryNode & VolumeNode.
              if (to_node->absolute_fuzzy_equals(*from_node, TOLERANCE))
                {
                  // Global dof_index for node in VolumeMesh.
                  const dof_id_type to_dof = to_node->dof_number(to_sys_number,
                                                                 to_var_number,
                                                                 to_n_comp - 1);

                  // Assign values to boundary in VolumeMesh.
                  to_sys->solution->set(to_dof, value[node]);
                }
            }
        }
    }
}

} // namespace libMesh
<|endoftext|>


<commit_before>
#include "polybuild.h"
#include "zip.h"

#if defined(__APPLE__) && defined(__MACH__)
#include <mach-o/dyld.h>
#endif

vector<BuildArg> args;
#define MAXFILENAME (256)

String getArg(String argName) {
	/*
	if(argName == "--config")
		return "ExampleProject.xml";

	if(argName == "--out")
		return "ExampleProject.polyapp";

		*/

	for(int i=0; i < args.size(); i++) {
		if(args[i].name == argName) {
			return args[i].value;
		}
	}
	return "";
}

uLong filetime(
    const char *f,
    tm_zip *tmzip,
    uLong *dt)
{
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;

  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME+1];
    int len = strlen(f);
    if (len > MAXFILENAME)
      len = MAXFILENAME;

    strncpy(name, f,MAXFILENAME-1);
    /* strncpy doesnt append the trailing NULL, of the string is too long. */
    name[ MAXFILENAME ] = '\0';

    if (name[len - 1] == '/')
      name[len - 1] = '\0';

    /* not all systems allow stat'ing a file with / appended */
#ifdef _WINDOWS

#else
    if (stat(name,&s)==0)
    {
      tm_t = s.st_mtime;
      ret = 1;
    }
#endif
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}

void addFileToZip(zipFile z, String filePath, String pathInZip, bool silent) {
			if(!silent)
				printf("Packaging %s as %s\n", filePath.c_str(), pathInZip.c_str());

                	zip_fileinfo zi;
                	zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
			zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
			 zi.dosDate = 0;
              	 	 zi.internal_fa = 0;
             		   zi.external_fa = 0;
             		   filetime(filePath.c_str(),&zi.tmz_date,&zi.dosDate);

			zipOpenNewFileInZip(z, pathInZip.c_str(), &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, 2);

			FILE *f = fopen(filePath.c_str(), "rb");
			fseek(f, 0, SEEK_END);
			long fileSize = ftell(f);
			fseek(f, 0, SEEK_SET);
			char *buf = (char*) malloc(fileSize);
			fread(buf, fileSize, 1, f);
			zipWriteInFileInZip(z, buf, fileSize);
			free(buf);
			fclose(f);

			zipCloseFileInZip(z);

}

void addFolderToZip(zipFile z, String folderPath, String parentFolder, bool silent) {
	std::vector<OSFileEntry> files = OSBasics::parseFolder(folderPath, false);
	for(int i=0; i < files.size(); i++) {
		if(files[i].type == OSFileEntry::TYPE_FILE) {

			String pathInZip;
			if(parentFolder == "") {
				pathInZip = files[i].name;
			} else {
				pathInZip = parentFolder + "/" + files[i].name;
			}

			addFileToZip(z, files[i].fullPath, pathInZip, silent);

		} else {
			if(parentFolder == "") {
				addFolderToZip(z, files[i].fullPath.c_str(), files[i].name, silent);
			} else {
				addFolderToZip(z, files[i].fullPath.c_str(), parentFolder + "/" + files[i].name, silent);
			}
		}
	}
}

#ifdef _WINDOWS
void wtoc(char* Dest, TCHAR* Source, int SourceSize)
{
for(int i = 0; i < SourceSize; ++i)
Dest[i] = (char)Source[i];
}
#endif

int main(int argc, char **argv) {

#if defined(__APPLE__) && defined(__MACH__)
    uint32_t bufsize = 2048;
	char path[bufsize];
	_NSGetExecutablePath(path, &bufsize);

	String basePath = path;
	vector<String> cpts = basePath.split("/");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("/");
	}
#elif defined (_WINDOWS)
	char path[2049];
	TCHAR tpath[2049];
	GetModuleFileName(NULL, (LPWSTR)tpath, 2048);
	wtoc(path, tpath, 2048);

	String basePath = path;
	vector<String> cpts = basePath.split("\\");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("\\");
	}
#else
	String basePath = PHYSFS_getBaseDir();
	vector<String> cpts = basePath.split("/");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("/");
	}
#endif

	printf("Polycode build tool v0.1.1\n");

	for(int i=0; i < argc; i++) {
		String argString = String(argv[i]);
		vector<String> bits = argString.split("=");
		if(bits.size() == 2) {
			BuildArg arg;
			arg.name = bits[0];
			arg.value = bits[1];
			args.push_back(arg);
		}

	}

	if(getArg("--config") == "") {
		printf("\n\nInput config XML missing. Use --config=path to specify.\n\n");
		return 1;
	}

	if(getArg("--out") == "") {
		printf("\n\nOutput file not specified. Use --out=outfile.polyapp to specify.\n\n");
		return 1;
	}

	char dirPath[4099];
#if defined(__APPLE__) && defined(__MACH__)
	getcwd(dirPath, sizeof(dirPath));
#elif defined (_WINDOWS)
	TCHAR tdirpath[4099];
	GetCurrentDirectory(4098, (LPWSTR)tdirpath);
	wtoc(dirPath, tdirpath, 4098);
#else
	getcwd(dirPath, sizeof(dirPath));
#endif
	String currentPath = String(dirPath);

	String configPath = getArg("--config");

	String finalPath = configPath;
	if(configPath[0] != '/') {

#ifdef _WINDOWS
		finalPath = currentPath+"\\"+configPath;
#else
		finalPath = currentPath+"/"+configPath;
#endif
	}

	finalPath = finalPath.replace(":", "");
	finalPath = finalPath.replace("\\", "/");
	finalPath = finalPath.substr(1, finalPath.length() - 1);

	printf("Reading config file from %s\n", finalPath.c_str());

	Object configFile;
	if(!configFile.loadFromXML(finalPath)) {
		printf("Specified config file doesn't exist!\n");
		return 1;
	}
	printf("OK!\n");
	// start required params

	String entryPoint;
	int defaultWidth;
	int defaultHeight;
	int frameRate = 60;
	int antiAliasingLevel = 0;
	bool fullScreen = false;
	float backgroundColorR = 0.2;
	float backgroundColorG = 0.2;
	float backgroundColorB = 0.2;

	if(configFile.root["entryPoint"]) {
		printf("Entry point: %s\n", configFile.root["entryPoint"]->stringVal.c_str());
		entryPoint = configFile.root["entryPoint"]->stringVal;
	} else {
		printf("Required parameter: \"entryPoint\" is missing from config file!\n");
		return 1;
	}

	if(configFile.root["defaultWidth"]) {
		printf("Width: %d\n", configFile.root["defaultWidth"]->intVal);
		defaultWidth = configFile.root["defaultWidth"]->intVal;
	} else {
		printf("Required parameter: \"defaultWidth\" is missing from config file!\n");
		return 1;
	}

	if(configFile.root["defaultHeight"]) {
		printf("Height: %d\n", configFile.root["defaultHeight"]->intVal);
		defaultHeight = configFile.root["defaultHeight"]->intVal;
	} else {
		printf("Required parameter: \"defaultHeight\" is missing from config file!\n");
		return 1;
	}

	// start optional params

	if(configFile.root["frameRate"]) {
		printf("Frame rate: %d\n", configFile.root["frameRate"]->intVal);
		frameRate = configFile.root["frameRate"]->intVal;
	}

	if(configFile.root["antiAliasingLevel"]) {
		printf("Anti-aliasing level: %d\n", configFile.root["antiAliasingLevel"]->intVal);
		antiAliasingLevel = configFile.root["antiAliasingLevel"]->intVal;
	}

	if(configFile.root["fullScreen"]) {
		fullScreen = configFile.root["fullScreen"]->boolVal;
		if(fullScreen) {
			printf("Full-screen: true\n");
		} else {
			printf("Full-screen: false\n");
		}
	}

	if(configFile.root["backgroundColor"]) {
		ObjectEntry *color = configFile.root["backgroundColor"];
		if((*color)["red"] && (*color)["green"] && (*color)["blue"]) {
			backgroundColorR = (*color)["red"]->NumberVal;
			backgroundColorG = (*color)["green"]->NumberVal;
			backgroundColorB = (*color)["blue"]->NumberVal;
			printf("Background color: %f %f %f\n", backgroundColorR, backgroundColorG, backgroundColorB);

		} else {
			printf("backgroundColor node specified, but missing all three color attributes (red,green,blue). Ignoring.\n");
		}
	}

	zipFile z = zipOpen(getArg("--out").c_str(), 0);

	Object runInfo;
	runInfo.root.name = "PolycodeApp";
	runInfo.root.addChild("entryPoint", entryPoint);
	runInfo.root.addChild("defaultHeight", defaultHeight);
	runInfo.root.addChild("defaultWidth", defaultWidth);
	runInfo.root.addChild("frameRate", frameRate);
	runInfo.root.addChild("antiAliasingLevel", antiAliasingLevel);
	runInfo.root.addChild("fullScreen", fullScreen);

	ObjectEntry *color = runInfo.root.addChild("backgroundColor");
	color->addChild("red", backgroundColorR);
	color->addChild("green", backgroundColorG);
	color->addChild("blue", backgroundColorB);

	addFileToZip(z, entryPoint, entryPoint, false);

	if(configFile.root["modules"]) {
#ifdef _WINDOWS
		String modulesPath = installPath + "Modules\\";
#else
		String modulesPath = installPath + "Modules/";
#endif

		ObjectEntry *modules = configFile.root["modules"];
		if(modules) {
			for(int i=0; i < modules->length; i++) {
				printf("Adding module: %s\n", (*modules)[i]->stringVal.c_str());
				String modulePath = modulesPath + (*modules)[i]->stringVal;
#ifdef _WINDOWS
				String moduleAPIPath = modulePath + "\\API";
				String moduleLibPath = modulePath + "\\Lib";
				moduleAPIPath = moduleAPIPath.replace("\\", "/");
				moduleAPIPath = moduleAPIPath.substr(2, moduleAPIPath.length() - 2);
				moduleLibPath = moduleLibPath.replace("\\", "/");
				moduleLibPath = moduleLibPath.substr(2, moduleLibPath.length() - 2);

#else
				String moduleAPIPath = modulePath + "/API";
				String moduleLibPath = modulePath + "/Lib";
#endif
				printf("Path:%s\n", moduleAPIPath.c_str());

				addFolderToZip(z, moduleAPIPath, "", false);
				addFolderToZip(z, moduleLibPath, "__lib", false);

				//String module = configFile.root["entryPoint"]->stringVal;
			}
			runInfo.root.addChild(configFile.root["modules"]);
		}
	}

	if(configFile.root["packedItems"]) {
		ObjectEntry *packed = configFile.root["packedItems"];
		if(packed) {
			for(int i=0; i < packed->length; i++) {
				ObjectEntry *entryPath = (*(*packed)[i])["path"];
				ObjectEntry *entryType = (*(*packed)[i])["type"];
				if(entryPath && entryType) {
					if(entryType->stringVal == "folder") {
						addFolderToZip(z, entryPath->stringVal, entryPath->stringVal, false);
					} else {
						addFileToZip(z, entryPath->stringVal, entryPath->stringVal, false);
					}
				}
			}
			runInfo.root.addChild(configFile.root["packedItems"]);
		}
	}

	runInfo.saveToXML("runinfo_tmp_zzzz.polyrun");
	addFileToZip(z, "runinfo_tmp_zzzz.polyrun", "runinfo.polyrun", true);

	//addFolderToZip(z, getArg("--project"), "");

	zipClose(z, "");

	OSBasics::removeItem("runinfo_tmp_zzzz.polyrun");

	return 0;
}
<commit_msg>Fixed code that came in with the Windows port, pretty sure this isn't useful on Unix or Mac.<commit_after>
#include "polybuild.h"
#include "zip.h"

#if defined(__APPLE__) && defined(__MACH__)
#include <mach-o/dyld.h>
#endif

vector<BuildArg> args;
#define MAXFILENAME (256)

String getArg(String argName) {
	/*
	if(argName == "--config")
		return "ExampleProject.xml";

	if(argName == "--out")
		return "ExampleProject.polyapp";

		*/

	for(int i=0; i < args.size(); i++) {
		if(args[i].name == argName) {
			return args[i].value;
		}
	}
	return "";
}

uLong filetime(
    const char *f,
    tm_zip *tmzip,
    uLong *dt)
{
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;

  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME+1];
    int len = strlen(f);
    if (len > MAXFILENAME)
      len = MAXFILENAME;

    strncpy(name, f,MAXFILENAME-1);
    /* strncpy doesnt append the trailing NULL, of the string is too long. */
    name[ MAXFILENAME ] = '\0';

    if (name[len - 1] == '/')
      name[len - 1] = '\0';

    /* not all systems allow stat'ing a file with / appended */
#ifdef _WINDOWS

#else
    if (stat(name,&s)==0)
    {
      tm_t = s.st_mtime;
      ret = 1;
    }
#endif
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}

void addFileToZip(zipFile z, String filePath, String pathInZip, bool silent) {
			if(!silent)
				printf("Packaging %s as %s\n", filePath.c_str(), pathInZip.c_str());

                	zip_fileinfo zi;
                	zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
			zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
			 zi.dosDate = 0;
              	 	 zi.internal_fa = 0;
             		   zi.external_fa = 0;
             		   filetime(filePath.c_str(),&zi.tmz_date,&zi.dosDate);

			zipOpenNewFileInZip(z, pathInZip.c_str(), &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, 2);

			FILE *f = fopen(filePath.c_str(), "rb");
			fseek(f, 0, SEEK_END);
			long fileSize = ftell(f);
			fseek(f, 0, SEEK_SET);
			char *buf = (char*) malloc(fileSize);
			fread(buf, fileSize, 1, f);
			zipWriteInFileInZip(z, buf, fileSize);
			free(buf);
			fclose(f);

			zipCloseFileInZip(z);

}

void addFolderToZip(zipFile z, String folderPath, String parentFolder, bool silent) {
	std::vector<OSFileEntry> files = OSBasics::parseFolder(folderPath, false);
	for(int i=0; i < files.size(); i++) {
		if(files[i].type == OSFileEntry::TYPE_FILE) {

			String pathInZip;
			if(parentFolder == "") {
				pathInZip = files[i].name;
			} else {
				pathInZip = parentFolder + "/" + files[i].name;
			}

			addFileToZip(z, files[i].fullPath, pathInZip, silent);

		} else {
			if(parentFolder == "") {
				addFolderToZip(z, files[i].fullPath.c_str(), files[i].name, silent);
			} else {
				addFolderToZip(z, files[i].fullPath.c_str(), parentFolder + "/" + files[i].name, silent);
			}
		}
	}
}

#ifdef _WINDOWS
void wtoc(char* Dest, TCHAR* Source, int SourceSize)
{
for(int i = 0; i < SourceSize; ++i)
Dest[i] = (char)Source[i];
}
#endif

int main(int argc, char **argv) {

#if defined(__APPLE__) && defined(__MACH__)
    uint32_t bufsize = 2048;
	char path[bufsize];
	_NSGetExecutablePath(path, &bufsize);

	String basePath = path;
	vector<String> cpts = basePath.split("/");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("/");
	}
#elif defined (_WINDOWS)
	char path[2049];
	TCHAR tpath[2049];
	GetModuleFileName(NULL, (LPWSTR)tpath, 2048);
	wtoc(path, tpath, 2048);

	String basePath = path;
	vector<String> cpts = basePath.split("\\");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("\\");
	}
#else
	String basePath = PHYSFS_getBaseDir();
	vector<String> cpts = basePath.split("/");
	String installPath = "";
	for(int i=0; i < cpts.size() - 2; i++) {
		installPath = installPath + cpts[i];
		installPath += String("/");
	}
#endif

	printf("Polycode build tool v0.1.1\n");

	for(int i=0; i < argc; i++) {
		String argString = String(argv[i]);
		vector<String> bits = argString.split("=");
		if(bits.size() == 2) {
			BuildArg arg;
			arg.name = bits[0];
			arg.value = bits[1];
			args.push_back(arg);
		}

	}

	if(getArg("--config") == "") {
		printf("\n\nInput config XML missing. Use --config=path to specify.\n\n");
		return 1;
	}

	if(getArg("--out") == "") {
		printf("\n\nOutput file not specified. Use --out=outfile.polyapp to specify.\n\n");
		return 1;
	}

	char dirPath[4099];
#if defined(__APPLE__) && defined(__MACH__)
	getcwd(dirPath, sizeof(dirPath));
#elif defined (_WINDOWS)
	TCHAR tdirpath[4099];
	GetCurrentDirectory(4098, (LPWSTR)tdirpath);
	wtoc(dirPath, tdirpath, 4098);
#else
	getcwd(dirPath, sizeof(dirPath));
#endif
	String currentPath = String(dirPath);

	String configPath = getArg("--config");

	String finalPath = configPath;
	if(configPath[0] != '/') {

#ifdef _WINDOWS
		finalPath = currentPath+"\\"+configPath;
#else
		finalPath = currentPath+"/"+configPath;
#endif
	}

#ifdef _WINDOWS
	finalPath = finalPath.replace(":", "");
	finalPath = finalPath.replace("\\", "/");
	finalPath = finalPath.substr(1, finalPath.length() - 1);
#endif

	printf("Reading config file from %s\n", finalPath.c_str());

	Object configFile;
	if(!configFile.loadFromXML(finalPath)) {
		printf("Specified config file doesn't exist!\n");
		return 1;
	}
	printf("OK!\n");
	// start required params

	String entryPoint;
	int defaultWidth;
	int defaultHeight;
	int frameRate = 60;
	int antiAliasingLevel = 0;
	bool fullScreen = false;
	float backgroundColorR = 0.2;
	float backgroundColorG = 0.2;
	float backgroundColorB = 0.2;

	if(configFile.root["entryPoint"]) {
		printf("Entry point: %s\n", configFile.root["entryPoint"]->stringVal.c_str());
		entryPoint = configFile.root["entryPoint"]->stringVal;
	} else {
		printf("Required parameter: \"entryPoint\" is missing from config file!\n");
		return 1;
	}

	if(configFile.root["defaultWidth"]) {
		printf("Width: %d\n", configFile.root["defaultWidth"]->intVal);
		defaultWidth = configFile.root["defaultWidth"]->intVal;
	} else {
		printf("Required parameter: \"defaultWidth\" is missing from config file!\n");
		return 1;
	}

	if(configFile.root["defaultHeight"]) {
		printf("Height: %d\n", configFile.root["defaultHeight"]->intVal);
		defaultHeight = configFile.root["defaultHeight"]->intVal;
	} else {
		printf("Required parameter: \"defaultHeight\" is missing from config file!\n");
		return 1;
	}

	// start optional params

	if(configFile.root["frameRate"]) {
		printf("Frame rate: %d\n", configFile.root["frameRate"]->intVal);
		frameRate = configFile.root["frameRate"]->intVal;
	}

	if(configFile.root["antiAliasingLevel"]) {
		printf("Anti-aliasing level: %d\n", configFile.root["antiAliasingLevel"]->intVal);
		antiAliasingLevel = configFile.root["antiAliasingLevel"]->intVal;
	}

	if(configFile.root["fullScreen"]) {
		fullScreen = configFile.root["fullScreen"]->boolVal;
		if(fullScreen) {
			printf("Full-screen: true\n");
		} else {
			printf("Full-screen: false\n");
		}
	}

	if(configFile.root["backgroundColor"]) {
		ObjectEntry *color = configFile.root["backgroundColor"];
		if((*color)["red"] && (*color)["green"] && (*color)["blue"]) {
			backgroundColorR = (*color)["red"]->NumberVal;
			backgroundColorG = (*color)["green"]->NumberVal;
			backgroundColorB = (*color)["blue"]->NumberVal;
			printf("Background color: %f %f %f\n", backgroundColorR, backgroundColorG, backgroundColorB);

		} else {
			printf("backgroundColor node specified, but missing all three color attributes (red,green,blue). Ignoring.\n");
		}
	}

	zipFile z = zipOpen(getArg("--out").c_str(), 0);

	Object runInfo;
	runInfo.root.name = "PolycodeApp";
	runInfo.root.addChild("entryPoint", entryPoint);
	runInfo.root.addChild("defaultHeight", defaultHeight);
	runInfo.root.addChild("defaultWidth", defaultWidth);
	runInfo.root.addChild("frameRate", frameRate);
	runInfo.root.addChild("antiAliasingLevel", antiAliasingLevel);
	runInfo.root.addChild("fullScreen", fullScreen);

	ObjectEntry *color = runInfo.root.addChild("backgroundColor");
	color->addChild("red", backgroundColorR);
	color->addChild("green", backgroundColorG);
	color->addChild("blue", backgroundColorB);

	addFileToZip(z, entryPoint, entryPoint, false);

	if(configFile.root["modules"]) {
#ifdef _WINDOWS
		String modulesPath = installPath + "Modules\\";
#else
		String modulesPath = installPath + "Modules/";
#endif

		ObjectEntry *modules = configFile.root["modules"];
		if(modules) {
			for(int i=0; i < modules->length; i++) {
				printf("Adding module: %s\n", (*modules)[i]->stringVal.c_str());
				String modulePath = modulesPath + (*modules)[i]->stringVal;
#ifdef _WINDOWS
				String moduleAPIPath = modulePath + "\\API";
				String moduleLibPath = modulePath + "\\Lib";
				moduleAPIPath = moduleAPIPath.replace("\\", "/");
				moduleAPIPath = moduleAPIPath.substr(2, moduleAPIPath.length() - 2);
				moduleLibPath = moduleLibPath.replace("\\", "/");
				moduleLibPath = moduleLibPath.substr(2, moduleLibPath.length() - 2);

#else
				String moduleAPIPath = modulePath + "/API";
				String moduleLibPath = modulePath + "/Lib";
#endif
				printf("Path:%s\n", moduleAPIPath.c_str());

				addFolderToZip(z, moduleAPIPath, "", false);
				addFolderToZip(z, moduleLibPath, "__lib", false);

				//String module = configFile.root["entryPoint"]->stringVal;
			}
			runInfo.root.addChild(configFile.root["modules"]);
		}
	}

	if(configFile.root["packedItems"]) {
		ObjectEntry *packed = configFile.root["packedItems"];
		if(packed) {
			for(int i=0; i < packed->length; i++) {
				ObjectEntry *entryPath = (*(*packed)[i])["path"];
				ObjectEntry *entryType = (*(*packed)[i])["type"];
				if(entryPath && entryType) {
					if(entryType->stringVal == "folder") {
						addFolderToZip(z, entryPath->stringVal, entryPath->stringVal, false);
					} else {
						addFileToZip(z, entryPath->stringVal, entryPath->stringVal, false);
					}
				}
			}
			runInfo.root.addChild(configFile.root["packedItems"]);
		}
	}

	runInfo.saveToXML("runinfo_tmp_zzzz.polyrun");
	addFileToZip(z, "runinfo_tmp_zzzz.polyrun", "runinfo.polyrun", true);

	//addFolderToZip(z, getArg("--project"), "");

	zipClose(z, "");

	OSBasics::removeItem("runinfo_tmp_zzzz.polyrun");

	return 0;
}
<|endoftext|>


<commit_before>/**
 * \file commands.hxx
 * Interface definition for encapsulated commands.
 * Started Spring 2001 by David Megginson, david@megginson.com
 * This code is released into the Public Domain.
 *
 * $Id$
 */

#include <simgear/compiler.h>
#include "SGBinding.hxx"

SGBinding::SGBinding()
  : _command(0),
    _arg(new SGPropertyNode),
    _setting(0)
{
}

SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root)
  : _command(0),
    _arg(0),
    _setting(0)
{
  read(node, root);
}

SGBinding::~SGBinding()
{
  if(_arg && _arg->getParent())
    _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false);
}

void
SGBinding::read(const SGPropertyNode* node, SGPropertyNode* root)
{
  const SGPropertyNode * conditionNode = node->getChild("condition");
  if (conditionNode != 0)
    setCondition(sgReadCondition(root, conditionNode));

  _command_name = node->getStringValue("command", "");
  if (_command_name.empty()) {
    SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
    _command = 0;
    return;
  }

  _arg = const_cast<SGPropertyNode*>(node);
  _setting = 0;
}

void
SGBinding::fire () const
{
  if (test()) {
    if (_command == 0)
      _command = SGCommandMgr::instance()->getCommand(_command_name);
    if (_command == 0) {
      SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
    } else if (!(*_command)(_arg)) {
      SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
             << _command_name);
    }
  }
}

void
SGBinding::fire (double offset, double max) const
{
  if (test()) {
    _arg->setDoubleValue("offset", offset/max);
    fire();
  }
}

void
SGBinding::fire (double setting) const
{
  if (test()) {
                                // A value is automatically added to
                                // the args
    if (_setting == 0)          // save the setting node for efficiency
      _setting = _arg->getChild("setting", 0, true);
    _setting->setDoubleValue(setting);
    fire();
  }
}
<commit_msg>Csaba HALASZ: set _arg even if there's no <command> (crash fix)<commit_after>/**
 * \file commands.hxx
 * Interface definition for encapsulated commands.
 * Started Spring 2001 by David Megginson, david@megginson.com
 * This code is released into the Public Domain.
 *
 * $Id$
 */

#include <simgear/compiler.h>
#include "SGBinding.hxx"

SGBinding::SGBinding()
  : _command(0),
    _arg(new SGPropertyNode),
    _setting(0)
{
}

SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root)
  : _command(0),
    _arg(0),
    _setting(0)
{
  read(node, root);
}

SGBinding::~SGBinding()
{
  if(_arg && _arg->getParent())
    _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false);
}

void
SGBinding::read(const SGPropertyNode* node, SGPropertyNode* root)
{
  const SGPropertyNode * conditionNode = node->getChild("condition");
  if (conditionNode != 0)
    setCondition(sgReadCondition(root, conditionNode));

  _command_name = node->getStringValue("command", "");
  if (_command_name.empty()) {
    SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
    _command = 0;
  }

  _arg = const_cast<SGPropertyNode*>(node);
  _setting = 0;
}

void
SGBinding::fire () const
{
  if (test()) {
    if (_command == 0)
      _command = SGCommandMgr::instance()->getCommand(_command_name);
    if (_command == 0) {
      SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
    } else if (!(*_command)(_arg)) {
      SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
             << _command_name);
    }
  }
}

void
SGBinding::fire (double offset, double max) const
{
  if (test()) {
    _arg->setDoubleValue("offset", offset/max);
    fire();
  }
}

void
SGBinding::fire (double setting) const
{
  if (test()) {
                                // A value is automatically added to
                                // the args
    if (_setting == 0)          // save the setting node for efficiency
      _setting = _arg->getChild("setting", 0, true);
    _setting->setDoubleValue(setting);
    fire();
  }
}
<|endoftext|>


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

#include <easyx\easyx.hpp>

#include <windows.h>
#include <xinput.h>
#include <queue>

#define LANALOG_THRESHOLD_X   (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE + data::thresholds[id][0])
#define LANALOG_THRESHOLD_Y   (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE + data::thresholds[id][1])
#define RANALOG_THRESHOLD_X   (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE + data::thresholds[id][2])
#define RANALOG_THRESHOLD_Y   (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE + data::thresholds[id][3])
#define LTRIGGER_ANGLE(ID)    data::gamepad_states[ID].Gamepad.bLeftTrigger
#define RTRIGGER_ANGLE(ID)    data::gamepad_states[ID].Gamepad.bRightTrigger

namespace easyx {
	namespace data {
		const ButtonID button_ids[] = {
			XINPUT_GAMEPAD_START,
			XINPUT_GAMEPAD_BACK,
			XINPUT_GAMEPAD_DPAD_UP,
			XINPUT_GAMEPAD_DPAD_DOWN,
			XINPUT_GAMEPAD_DPAD_LEFT,
			XINPUT_GAMEPAD_DPAD_RIGHT,
			XINPUT_GAMEPAD_A,
			XINPUT_GAMEPAD_B,
			XINPUT_GAMEPAD_X,
			XINPUT_GAMEPAD_Y,
			XINPUT_GAMEPAD_LEFT_THUMB,
			XINPUT_GAMEPAD_RIGHT_THUMB,
			XINPUT_GAMEPAD_LEFT_SHOULDER,
			XINPUT_GAMEPAD_RIGHT_SHOULDER
		};

		bool connections[XUSER_MAX_COUNT];
		XINPUT_STATE gamepad_states[XUSER_MAX_COUNT];
		bool button_states[XUSER_MAX_COUNT][14];
		int16_t thresholds[XUSER_MAX_COUNT][6];
		int16_t stickangles[XUSER_MAX_COUNT][4];
		uint8_t triggerangles[XUSER_MAX_COUNT][2];

		std::queue<Event> events;
	}

	namespace detect {
		/*
		 * detect::connect() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has just connected.
		 * */
		void connect(GamepadID id) {
			if (data::connections[id] == false) {
				data::connections[id] = true;
				data::events.push(Event(id, EASYX_EVENT_CONNECT, id));
			}
		}

		/*
		 * detect::disconnect() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has just disconnected.
		 * */
		void disconnect(GamepadID id) {
			if (data::connections[id]) {
				data::connections[id] = false;
				data::events.push(Event(id, EASYX_EVENT_DISCONNECT, id));
			}
		}

		/*
		 * detect::triggers() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has had one of, or both of, its
		 * triggers pressed down at any angle other than zero. The last two
		 * lines are necessary for the function to determine if the current trigger
		 * is different from the previous trigger state.
		 * */
		void triggers(GamepadID id) {
			if (LTRIGGER_ANGLE(id)) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTRIGGER, LTRIGGER_ANGLE(id)));
			} else if(data::triggerangles[id][0]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTRIGGER));
			}

			if (RTRIGGER_ANGLE(id)) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTRIGGER, RTRIGGER_ANGLE(id)));
			} else if(data::triggerangles[id][1]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTRIGGER));
			}

			data::triggerangles[id][0] = LTRIGGER_ANGLE(id);
			data::triggerangles[id][1] = RTRIGGER_ANGLE(id);
		}

		/*
		 * detect::sticks() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines the state of both of the analog sticks, on both the
		 * X and Y axes. Because of the nature of determining if an analog
		 * stick is considered pressed or stationary, preprocessor definitions
		 * are used to cut down of the verbosity of the if statements. The
		 * definitions can be found at the beginning of this source file.
		 *
		 * A loop could have been used in this function, but since it is very
		 * unlikely that XInput will ever support more than two analog sticks
		 * one is not used for the sake of improving performance.
		 * */
		void sticks(GamepadID id) {
			if (data::gamepad_states[id].Gamepad.sThumbLX >= LANALOG_THRESHOLD_X || data::gamepad_states[id].Gamepad.sThumbLX <= -LANALOG_THRESHOLD_X) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTHUMB_X, data::gamepad_states[id].Gamepad.sThumbLX));
				data::stickangles[id][0] = data::gamepad_states[id].Gamepad.sThumbLX;
			} else if(data::stickangles[id][0]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTHUMB_X));
				data::stickangles[id][0] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbLY >= LANALOG_THRESHOLD_Y || data::gamepad_states[id].Gamepad.sThumbLY <= -LANALOG_THRESHOLD_Y) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTHUMB_Y, data::gamepad_states[id].Gamepad.sThumbLY));
				data::stickangles[id][1] = data::gamepad_states[id].Gamepad.sThumbLY;
			} else if(data::stickangles[id][1]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTHUMB_Y));
				data::stickangles[id][1] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbRX >= RANALOG_THRESHOLD_X || data::gamepad_states[id].Gamepad.sThumbRX <= -RANALOG_THRESHOLD_X) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTHUMB_X, data::gamepad_states[id].Gamepad.sThumbRX));
				data::stickangles[id][2] = data::gamepad_states[id].Gamepad.sThumbRX;
			} else if(data::stickangles[id][2]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTHUMB_X));
				data::stickangles[id][2] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbRY >= RANALOG_THRESHOLD_Y || data::gamepad_states[id].Gamepad.sThumbRY <= -RANALOG_THRESHOLD_Y) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTHUMB_Y, data::gamepad_states[id].Gamepad.sThumbRY));
				data::stickangles[id][3] = data::gamepad_states[id].Gamepad.sThumbRY;
			} else if(data::stickangles[id][3]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTHUMB_Y));
				data::stickangles[id][3] = 0;
			}
		}

		/*
		 * buttons() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines the state of any of the pressable buttons (e.g. A, B, X, Y,
		 * Start, Left Trigger). Only the buttons detected in this function are
		 * applicable to all three PRESS, DOWN, and RELEASE events.
		 * */
		void buttons(GamepadID id) {
			for (char i=0; i<14; ++i) {
				if (data::gamepad_states[id].Gamepad.wButtons & data::button_ids[i]) {
					if (data::button_states[id][i] == false) {
						data::button_states[id][i] = true;
						data::events.push(Event(id, EASYX_EVENT_PRESS, data::button_ids[i]));
					}
					data::events.push(Event(id, EASYX_EVENT_DOWN, data::button_ids[i]));
				} else if (data::button_states[id][i]) {
					data::button_states[id][i] = false;
					data::events.push(Event(id, EASYX_EVENT_RELEASE, data::button_ids[i]));
				}
			}
		}
	}

	/*
	 * update() returns nothing
	 *
	 * Updates all gamepads, detecting any connections, disconnections, or inputs.
	 * */
	void update() {
		for (GamepadID i=0; i<XUSER_MAX_COUNT; ++i) {
			if (XInputGetState(i, &data::gamepad_states[i]) == ERROR_SUCCESS) {
				detect::connect(i);
				detect::buttons(i);
				detect::triggers(i);
				detect::sticks(i);
			} else {
				detect::disconnect(i);
			}
		}
	}

	/*
	 * poll() returns bool
	 *
		* @param  Pointer to the object where the event should be stored.
	 *
	 * Is used in a loop, typically a while, to pop all events out of
	 * the event queue. Events will popped off in the order that they
	 * occurred (i.e. FIFO order).
	 * */
	bool poll(PEvent evt) {
		if (data::events.empty() == false) {
			*evt = data::events.front();
			data::events.pop();
			return true;
		}

		*evt = Event();
		return false;
	}

	/*
	 * set_analog_threshold() returns nothing
	 *
		* @param  The id of the gamepad to have its threshold set.
		* @param  The id of the analog stick(s) to set.
		* @param  The new threshold.
	 *
	 * Sets the threshold that the given analog stick(s) must pass for
	 * it/them to be considered moved. By default the threshold is the
	 * XINPUT_GAMEPAD_LEFT/RIGHT_THUMB_DEADZONE values. The threshold set
	 * by this function will be added to those values, so passing the negative
	 * equivalent of the XInput deadzone definitions will effectively set
	 * the threshold to zero.
	 * */
	void set_analog_threshold(GamepadID gamepad, ButtonID id, int16_t amount) {
		switch (id) {
		case EASYX_LTHUMB:
			data::thresholds[gamepad][0] = amount;
			data::thresholds[gamepad][1] = amount;
			break;
		case EASYX_RTHUMB:
			data::thresholds[gamepad][2] = amount;
			data::thresholds[gamepad][3] = amount;
			break;
		case EASYX_LTHUMB_X:
			data::thresholds[gamepad][0] = amount;
			break;
		case EASYX_LTHUMB_Y:
			data::thresholds[gamepad][1] = amount;
			break;
		case EASYX_RTHUMB_X:
			data::thresholds[gamepad][2] = amount;
			break;
		case EASYX_RTHUMB_Y:
			data::thresholds[gamepad][3] = amount;
			break;
		}
	}

	/*
	 * set_vibration() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate both sides.
	 *
	 * Vibrates the passed gamepad by the passed amount.
	 * */
	void set_vibration(GamepadID gamepad, uint16_t amount) {
		set_vibration(gamepad, amount, amount);
	}

	/*
	 * set_vibration() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate the left side.
		* @param  The amount to vibrate the right side.
	 *
	 * Vibrates the passed gamepad by the passed left/right amounts.
	 * */
	void set_vibration(GamepadID gamepad, uint16_t left, uint16_t right) {
		XINPUT_VIBRATION vibrate;
		ZeroMemory(&vibrate, sizeof(XINPUT_VIBRATION));

		vibrate.wLeftMotorSpeed = left;
		vibrate.wRightMotorSpeed = right;

		XInputSetState(gamepad, &vibrate);
	}

	/*
	 * set_vibration_level() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate both sides.
	 *
	 * Vibrates the passed gamepad by the passed amount. Unlike the
	 * setVibration() functions, this is based on the percentage of how
	 * much to vibrate. In other words 0.0f would mean 0% vibration,
	 * and 1.0f would mean 100% vibration.
	 * */
	void set_vibration_level(GamepadID gamepad, float amount) {
		set_vibration(gamepad, uint16_t(UINT16_MAX * amount), uint16_t(UINT16_MAX * amount));
	}

	/*
	 * set_vibration_level() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate the left side.
		* @param  The amount to vibrate the right side.
	 *
	 * Vibrates the passed gamepad by the passed left/right amounts.
	 * Unlike the setVibration() functions, this is based on the percentage of how
	 * much to vibrate. In other words 0.0f would mean 0% vibration,
	 * and 1.0f would mean 100% vibration.
	 * */
	void set_vibration_level(GamepadID gamepad, float left, float right) {
		set_vibration(gamepad, uint16_t(UINT16_MAX * left), uint16_t(UINT16_MAX * right));
	}
}<commit_msg>Update easyx.cpp<commit_after>/*
* EasyXInput
* http://tylerobrien.com
* https://github.com/TylerOBrien/EasyXInput
*
* Copyright (c) 2014 Tyler O'Brien
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* */

#include <easyx\easyx.hpp>

#include <windows.h>
#include <xinput.h>
#include <queue>

#define LANALOG_THRESHOLD_X   (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE + data::thresholds[id][0])
#define LANALOG_THRESHOLD_Y   (XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE + data::thresholds[id][1])
#define RANALOG_THRESHOLD_X   (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE + data::thresholds[id][2])
#define RANALOG_THRESHOLD_Y   (XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE + data::thresholds[id][3])
#define LTRIGGER_ANGLE(ID)    data::gamepad_states[ID].Gamepad.bLeftTrigger
#define RTRIGGER_ANGLE(ID)    data::gamepad_states[ID].Gamepad.bRightTrigger

namespace easyx {
	namespace data {
		const ButtonID button_ids[] = {
			XINPUT_GAMEPAD_START,
			XINPUT_GAMEPAD_BACK,
			XINPUT_GAMEPAD_DPAD_UP,
			XINPUT_GAMEPAD_DPAD_DOWN,
			XINPUT_GAMEPAD_DPAD_LEFT,
			XINPUT_GAMEPAD_DPAD_RIGHT,
			XINPUT_GAMEPAD_A,
			XINPUT_GAMEPAD_B,
			XINPUT_GAMEPAD_X,
			XINPUT_GAMEPAD_Y,
			XINPUT_GAMEPAD_LEFT_THUMB,
			XINPUT_GAMEPAD_RIGHT_THUMB,
			XINPUT_GAMEPAD_LEFT_SHOULDER,
			XINPUT_GAMEPAD_RIGHT_SHOULDER
		};

		bool connections[XUSER_MAX_COUNT];
		XINPUT_STATE gamepad_states[XUSER_MAX_COUNT];
		bool button_states[XUSER_MAX_COUNT][14];
		int16_t thresholds[XUSER_MAX_COUNT][6];
		int16_t stickangles[XUSER_MAX_COUNT][4];
		uint8_t triggerangles[XUSER_MAX_COUNT][2];

		std::queue<Event> events;
	}

	namespace detect {
		/*
		 * detect::connect() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has just connected.
		 * */
		void connect(GamepadID id) {
			if (data::connections[id] == false) {
				data::connections[id] = true;
				data::events.push(Event(id, EASYX_EVENT_CONNECT, id));
			}
		}

		/*
		 * detect::disconnect() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has just disconnected.
		 * */
		void disconnect(GamepadID id) {
			if (data::connections[id]) {
				data::connections[id] = false;
				data::events.push(Event(id, EASYX_EVENT_DISCONNECT, id));
			}
		}

		/*
		 * detect::triggers() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines if the passed gamepad has had one of, or both of, its
		 * triggers pressed down at any angle other than zero. The last two
		 * lines are necessary for the function to determine if the current trigger
		 * is different from the previous trigger state.
		 * */
		void triggers(GamepadID id) {
			if (LTRIGGER_ANGLE(id)) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTRIGGER, LTRIGGER_ANGLE(id)));
			} else if(data::triggerangles[id][0]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTRIGGER));
			}

			if (RTRIGGER_ANGLE(id)) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTRIGGER, RTRIGGER_ANGLE(id)));
			} else if(data::triggerangles[id][1]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTRIGGER));
			}

			data::triggerangles[id][0] = LTRIGGER_ANGLE(id);
			data::triggerangles[id][1] = RTRIGGER_ANGLE(id);
		}

		/*
		 * detect::sticks() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines the state of both of the analog sticks, on both the
		 * X and Y axes. Because of the nature of determining if an analog
		 * stick is considered pressed or stationary, preprocessor definitions
		 * are used to cut down of the verbosity of the if statements. The
		 * definitions can be found at the beginning of this source file.
		 *
		 * A loop could have been used in this function, but since it is very
		 * unlikely that XInput will ever support more than two analog sticks
		 * one is not used for the sake of improving performance.
		 * */
		void sticks(GamepadID id) {
			if (data::gamepad_states[id].Gamepad.sThumbLX >= LANALOG_THRESHOLD_X || data::gamepad_states[id].Gamepad.sThumbLX <= -LANALOG_THRESHOLD_X) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTHUMB_X, data::gamepad_states[id].Gamepad.sThumbLX));
				data::stickangles[id][0] = data::gamepad_states[id].Gamepad.sThumbLX;
			} else if(data::stickangles[id][0]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTHUMB_X));
				data::stickangles[id][0] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbLY >= LANALOG_THRESHOLD_Y || data::gamepad_states[id].Gamepad.sThumbLY <= -LANALOG_THRESHOLD_Y) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_LTHUMB_Y, data::gamepad_states[id].Gamepad.sThumbLY));
				data::stickangles[id][1] = data::gamepad_states[id].Gamepad.sThumbLY;
			} else if(data::stickangles[id][1]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_LTHUMB_Y));
				data::stickangles[id][1] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbRX >= RANALOG_THRESHOLD_X || data::gamepad_states[id].Gamepad.sThumbRX <= -RANALOG_THRESHOLD_X) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTHUMB_X, data::gamepad_states[id].Gamepad.sThumbRX));
				data::stickangles[id][2] = data::gamepad_states[id].Gamepad.sThumbRX;
			} else if(data::stickangles[id][2]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTHUMB_X));
				data::stickangles[id][2] = 0;
			}

			if (data::gamepad_states[id].Gamepad.sThumbRY >= RANALOG_THRESHOLD_Y || data::gamepad_states[id].Gamepad.sThumbRY <= -RANALOG_THRESHOLD_Y) {
				data::events.push(Event(id, EASYX_EVENT_DOWN, EASYX_RTHUMB_Y, data::gamepad_states[id].Gamepad.sThumbRY));
				data::stickangles[id][3] = data::gamepad_states[id].Gamepad.sThumbRY;
			} else if(data::stickangles[id][3]) {
				data::events.push(Event(id, EASYX_EVENT_RELEASE, EASYX_RTHUMB_Y));
				data::stickangles[id][3] = 0;
			}
		}

		/*
		 * buttons() returns nothing
		 *
			*	@param  The id of the gamepad.
		 *
		 * Determines the state of any of the pressable buttons (e.g. A, B, X, Y,
		 * Start, Left Trigger). Only the buttons detected in this function are
		 * applicable to all three PRESS, DOWN, and RELEASE events.
		 * */
		void buttons(GamepadID id) {
			for (char i=0; i<14; ++i) {
				if (data::gamepad_states[id].Gamepad.wButtons & data::button_ids[i]) {
					if (data::button_states[id][i] == false) {
						data::button_states[id][i] = true;
						data::events.push(Event(id, EASYX_EVENT_PRESS, data::button_ids[i]));
					}
					data::events.push(Event(id, EASYX_EVENT_DOWN, data::button_ids[i]));
				} else if (data::button_states[id][i]) {
					data::button_states[id][i] = false;
					data::events.push(Event(id, EASYX_EVENT_RELEASE, data::button_ids[i]));
				}
			}
		}
	}

	/*
	 * update() returns nothing
	 *
	 * Updates all gamepads, detecting any connections, disconnections, or inputs.
	 * */
	void update() {
		for (GamepadID i=0; i<XUSER_MAX_COUNT; ++i) {
			if (XInputGetState(i, &data::gamepad_states[i]) == ERROR_SUCCESS) {
				detect::connect(i);
				detect::buttons(i);
				detect::triggers(i);
				detect::sticks(i);
			} else {
				detect::disconnect(i);
			}
		}
	}

	/*
	 * poll() returns bool
	 *
		* @param  Pointer to the object where the event should be stored.
	 *
	 * Is used in a loop, typically a while, to pop all events out of
	 * the event queue. Events will popped off in the order that they
	 * occurred (i.e. FIFO order).
	 * */
	bool poll(PEvent evt) {
		if (data::events.empty() == false) {
			*evt = data::events.front();
			data::events.pop();
			return true;
		}

		*evt = Event();
		return false;
	}

	/*
	 * set_analog_threshold() returns nothing
	 *
		* @param  The id of the gamepad to have its threshold set.
		* @param  The id of the analog stick(s) to set.
		* @param  The new threshold.
	 *
	 * Sets the threshold that the given analog stick(s) must pass for
	 * it/them to be considered moved. By default the threshold is the
	 * XINPUT_GAMEPAD_LEFT/RIGHT_THUMB_DEADZONE values. The threshold set
	 * by this function will be added to those values, so passing the negative
	 * equivalent of the XInput deadzone definitions will effectively set
	 * the threshold to zero.
	 * */
	void set_analog_threshold(GamepadID gamepad, ButtonID id, int16_t amount) {
		switch (id) {
		case EASYX_LTHUMB:
			data::thresholds[gamepad][0] = amount;
			data::thresholds[gamepad][1] = amount;
			break;
		case EASYX_RTHUMB:
			data::thresholds[gamepad][2] = amount;
			data::thresholds[gamepad][3] = amount;
			break;
		case EASYX_LTHUMB_X:
			data::thresholds[gamepad][0] = amount;
			break;
		case EASYX_LTHUMB_Y:
			data::thresholds[gamepad][1] = amount;
			break;
		case EASYX_RTHUMB_X:
			data::thresholds[gamepad][2] = amount;
			break;
		case EASYX_RTHUMB_Y:
			data::thresholds[gamepad][3] = amount;
			break;
		}
	}

	/*
	 * set_vibration() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate both sides.
	 *
	 * Vibrates the passed gamepad by the passed amount.
	 * */
	void set_vibration(GamepadID gamepad, uint16_t amount) {
		set_vibration(gamepad, amount, amount);
	}

	/*
	 * set_vibration() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate the left side.
		* @param  The amount to vibrate the right side.
	 *
	 * Vibrates the passed gamepad by the passed left/right amounts.
	 * */
	void set_vibration(GamepadID gamepad, uint16_t left, uint16_t right) {
		XINPUT_VIBRATION vibrate;
		ZeroMemory(&vibrate, sizeof(XINPUT_VIBRATION));

		vibrate.wLeftMotorSpeed = left;
		vibrate.wRightMotorSpeed = right;

		XInputSetState(gamepad, &vibrate);
	}

	/*
	 * set_vibration_level() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate both sides.
	 *
	 * Vibrates the passed gamepad by the passed amount. Unlike the
	 * setVibration() functions, this is based on the percentage of how
	 * much to vibrate. In other words 0.0f would mean 0% vibration,
	 * and 1.0f would mean 100% vibration.
	 * */
	void set_vibration_level(GamepadID gamepad, float amount) {
		set_vibration(gamepad, uint16_t(UINT16_MAX * amount), uint16_t(UINT16_MAX * amount));
	}

	/*
	 * set_vibration_level() returns nothing
	 *
		* @param  The id of the gamepad to vibrate.
		* @param  The amount to vibrate the left side.
		* @param  The amount to vibrate the right side.
	 *
	 * Vibrates the passed gamepad by the passed left/right amounts.
	 * Unlike the setVibration() functions, this is based on the percentage of how
	 * much to vibrate. In other words 0.0f would mean 0% vibration,
	 * and 1.0f would mean 100% vibration.
	 * */
	void set_vibration_level(GamepadID gamepad, float left, float right) {
		set_vibration(gamepad, uint16_t(UINT16_MAX * left), uint16_t(UINT16_MAX * right));
	}
}
<|endoftext|>