<commit_before>#include "AIHandler.h"
#define SUCCESS 1
#define FAIL 0

AIHandler::AIHandler(){}
AIHandler::~AIHandler(){}
int AIHandler::Shutdown()
{
	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		delete this->m_AIComponents.at(i);
	}

	return SUCCESS;
}

int AIHandler::Initialize(int max)
{
	this->WaypointUpdated = false;
	this->m_nrOfAIComponents = 0;

	if (max <= 0)
	{
		// Don't allow negative or zero initiated components
		max = 2;
	}

	this->m_maxOfAIComponents = max;

	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		this->m_AIComponents.push_back(CreateAIComponent(-1));
	}

	return SUCCESS;
}
int AIHandler::Update(float deltaTime)
{
	for (int i = 0; i < this->m_nrOfAIComponents; i++)
	{
		if (this->m_AIComponents.at(i)->AP_active && this->m_AIComponents.at(i)->AP_triggered)
		{
			// AIComponent logic/behavior, movement of e.g. platforms
			DirectX::XMVECTOR pos = this->m_AIComponents.at(i)->AP_position;
			int currentWaypoint = this->m_AIComponents.at(i)->AP_latestWaypointID;
			int nrOfWaypoint = this->m_AIComponents.at(i)->AP_nrOfWaypoint;
			int pattern = this->m_AIComponents.at(i)->AP_pattern;
			int time = this->m_AIComponents.at(i)->AP_time;
			int direction = this->m_AIComponents.at(i)->AP_direction;

			if (pattern == 1)
			{
				if (currentWaypoint == 0 || currentWaypoint == nrOfWaypoint)
				{
					if (direction == 0)
						this->m_AIComponents.at(i)->AP_direction = 1;
					else
						this->m_AIComponents.at(i)->AP_direction = 0;
				}
			}
			else if (pattern == 3)
			{
				//TODO Round-trip pattern
			}
			else
			{
				//Identical to pattern 2 (Circular)
				if (direction == 0)
				{
					if (WaypointApprox(i))
					{
						currentWaypoint = this->m_AIComponents.at(i)->AP_nextWaypointID;
						this->m_AIComponents.at(i)->AP_nextWaypointID++;
						if (this->m_AIComponents.at(i)->AP_nextWaypointID >= this->m_AIComponents.at(i)->AP_nrOfWaypoint)
							this->m_AIComponents.at(i)->AP_nextWaypointID = 0;
					}
				}
				else
				{
					if (WaypointApprox(i))
					{
						currentWaypoint = this->m_AIComponents.at(i)->AP_nextWaypointID;
						this->m_AIComponents.at(i)->AP_nextWaypointID--;
						if (this->m_AIComponents.at(i)->AP_nextWaypointID <= this->m_AIComponents.at(i)->AP_nrOfWaypoint)
							this->m_AIComponents.at(i)->AP_nextWaypointID = nrOfWaypoint;
					}
				}
			}

			//Update position
			if (this->WaypointUpdated == false)
			{
				this->m_AIComponents.at(i)->AP_dir = DirectX::XMVector4Normalize(DirectX::XMVectorSubtract(
					this->m_AIComponents.at(i)->AP_waypoints[this->m_AIComponents.at(i)->AP_nextWaypointID],
					pos));
				this->WaypointUpdated = true;
			}

			DirectX::XMVECTOR v = DirectX::XMVECTOR();
			v = DirectX::XMVectorScale(DirectX::XMVector3Normalize(this->m_AIComponents.at(i)->AP_dir), this->m_AIComponents.at(i)->AP_speed);
			//v = DirectX::XMVectorScale(v, deltaTime);

			//this->m_AIComponents.at(i)->AP_position = DirectX::XMVectorMultiply(v, this->m_AIComponents.at(i)->AP_position);
			this->m_AIComponents.at(i)->AP_position = DirectX::XMVectorAdd(v, this->m_AIComponents.at(i)->AP_position);
		}
	}

	return SUCCESS;
}

void AIHandler::SetComponentActive(int compID)
{
	this->m_AIComponents.at(compID)->AP_active = true;
}

void AIHandler::SetComponentFalse(int compID)
{
	this->m_AIComponents.at(compID)->AP_active = false;
}

void AIHandler::SetEntityID(int compID, int entityID)
{
	this->m_AIComponents.at(compID)->AP_entityID = entityID;
}

void AIHandler::SetTriggered(int compID, bool triggered)
{
	this->m_AIComponents.at(compID)->AP_triggered = triggered;
}

void AIHandler::SetTime(int compID, int time)
{
	this->m_AIComponents.at(compID)->AP_time = time;
}

void AIHandler::SetSpeed(int compID, float speed)
{
	this->m_AIComponents.at(compID)->AP_speed = speed;
}

void AIHandler::SetDirection(int compID, int direction)
{
	this->m_AIComponents.at(compID)->AP_direction = direction;
}

void AIHandler::SetCurrentWaypoint(int compID, int latestWaypoint)
{
	this->m_AIComponents.at(compID)->AP_latestWaypointID = latestWaypoint;
}

void AIHandler::SetPattern(int compID, int pattern)
{
	this->m_AIComponents.at(compID)->AP_pattern = pattern;
}

void AIHandler::SetWaypoints(int compID, DirectX::XMVECTOR waypoints[])
{
	for (int i = 0; i < 8; i++)
	{
		this->m_AIComponents.at(compID)->AP_waypoints[i] = waypoints[i];
		this->m_AIComponents.at(compID)->AP_nrOfWaypoint++;
	}
}

int AIHandler::GetNrOfAIComponents() const
{
	return this->m_nrOfAIComponents;
}

DirectX::XMVECTOR AIHandler::GetPosition(int compID) const
{
	return this->m_AIComponents.at(compID)->AP_position;
}

AIComponent * AIHandler::GetNextAvailableComponents()
{
	// Increase vector by initiating new AIComponents
	if (this->m_nrOfAIComponents == this->m_maxOfAIComponents)
	{
		int oldMax = this->m_maxOfAIComponents;
		this->m_maxOfAIComponents += this->m_maxOfAIComponents;
		for (int i = oldMax; i < this->m_maxOfAIComponents; i++)
		{
			this->m_AIComponents.push_back(CreateAIComponent(i));
		}
	}
	this->m_nrOfAIComponents++;
	return this->m_AIComponents[this->m_nrOfAIComponents - 1];
}

AIComponent* AIHandler::CreateAIComponent(int entityID)
{
	AIComponent* newComponent = nullptr;
	newComponent = new AIComponent;

	newComponent->AP_active = 0;
	newComponent->AP_entityID = entityID;
	newComponent->AP_position = DirectX::XMVECTOR();

	newComponent->AP_triggered = false;
	newComponent->AP_pattern = 0;
	newComponent->AP_time = 0;
	newComponent->AP_speed = 0;
	newComponent->AP_direction = 0;
	newComponent->AP_nextWaypointID = 0;
	newComponent->AP_latestWaypointID = 0;
	newComponent->AP_nrOfWaypoint = 0;

	for (int i = 0; i < 8; i++)
	{
		newComponent->AP_waypoints[i] = DirectX::XMVECTOR();
	}

	return newComponent;
}

bool AIHandler::WaypointApprox(int compID)
{
	int current = this->m_AIComponents.at(compID)->AP_latestWaypointID;
	int next = this->m_AIComponents.at(compID)->AP_nextWaypointID;

	DirectX::XMVECTOR v = DirectX::XMVectorSubtract(this->m_AIComponents.at(compID)->AP_waypoints[next]
		,this->m_AIComponents.at(compID)->AP_waypoints[current]);

	float length = VectorLength(v);

	if (length < 0.01)
	{
		this->WaypointUpdated = false;
		return true;
	}

	return false;
}

int AIHandler::GetNextWaypoint(int compID, int pattern)
{
	int next = this->m_AIComponents.at(compID)->AP_latestWaypointID;
	int current = this->m_AIComponents.at(compID)->AP_nextWaypointID;

	if (pattern == 1)
	{
		//TODO Linear pattern next waypoint logic
	}
	else
	{

	}

	if (next == current)
	{

	}

	this->m_AIComponents.at(compID)->AP_latestWaypointID;
	this->m_AIComponents.at(compID)->AP_direction;

	return 0;
}

float AIHandler::VectorLength(DirectX::XMVECTOR v)
{
	float length = DirectX::XMVectorGetX(DirectX::XMVector3Length(v));
	return length;
}
<commit_msg>FIX WaypointApprox compare for floats did not work<commit_after>#include "AIHandler.h"
#define SUCCESS 1
#define FAIL 0

AIHandler::AIHandler(){}
AIHandler::~AIHandler(){}
int AIHandler::Shutdown()
{
	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		delete this->m_AIComponents.at(i);
	}

	return SUCCESS;
}

int AIHandler::Initialize(int max)
{
	this->WaypointUpdated = false;
	this->m_nrOfAIComponents = 0;

	if (max <= 0)
	{
		// Don't allow negative or zero initiated components
		max = 2;
	}

	this->m_maxOfAIComponents = max;

	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		this->m_AIComponents.push_back(CreateAIComponent(-1));
	}

	return SUCCESS;
}
int AIHandler::Update(float deltaTime)
{
	for (int i = 0; i < this->m_nrOfAIComponents; i++)
	{
		if (this->m_AIComponents.at(i)->AP_active && this->m_AIComponents.at(i)->AP_triggered)
		{
			// AIComponent logic/behavior, movement of e.g. platforms
			DirectX::XMVECTOR pos = this->m_AIComponents.at(i)->AP_position;
			int currentWaypoint = this->m_AIComponents.at(i)->AP_latestWaypointID;
			int nrOfWaypoint = this->m_AIComponents.at(i)->AP_nrOfWaypoint;
			int pattern = this->m_AIComponents.at(i)->AP_pattern;
			int time = this->m_AIComponents.at(i)->AP_time;
			int direction = this->m_AIComponents.at(i)->AP_direction;

			if (pattern == 1)
			{
				if (currentWaypoint == 0 || currentWaypoint == nrOfWaypoint)
				{
					if (direction == 0)
						this->m_AIComponents.at(i)->AP_direction = 1;
					else
						this->m_AIComponents.at(i)->AP_direction = 0;
				}
			}
			else if (pattern == 3)
			{
				//TODO Round-trip pattern
			}
			else
			{
				//Identical to pattern 2 (Circular)
				if (direction == 0)
				{
					if (WaypointApprox(i))
					{
						currentWaypoint = this->m_AIComponents.at(i)->AP_nextWaypointID;
						this->m_AIComponents.at(i)->AP_nextWaypointID++;
						if (this->m_AIComponents.at(i)->AP_nextWaypointID >= this->m_AIComponents.at(i)->AP_nrOfWaypoint)
							this->m_AIComponents.at(i)->AP_nextWaypointID = 0;
					}
				}
				else
				{
					if (WaypointApprox(i))
					{
						currentWaypoint = this->m_AIComponents.at(i)->AP_nextWaypointID;
						this->m_AIComponents.at(i)->AP_nextWaypointID--;
						if (this->m_AIComponents.at(i)->AP_nextWaypointID <= this->m_AIComponents.at(i)->AP_nrOfWaypoint)
							this->m_AIComponents.at(i)->AP_nextWaypointID = nrOfWaypoint;
					}
				}
			}

			//Update position
			if (this->WaypointUpdated == false)
			{
				this->m_AIComponents.at(i)->AP_dir = DirectX::XMVector4Normalize(DirectX::XMVectorSubtract(
					this->m_AIComponents.at(i)->AP_waypoints[this->m_AIComponents.at(i)->AP_nextWaypointID],
					pos));
				this->WaypointUpdated = true;
			}

			DirectX::XMVECTOR v = DirectX::XMVECTOR();
			v = DirectX::XMVectorScale(DirectX::XMVector3Normalize(this->m_AIComponents.at(i)->AP_dir), this->m_AIComponents.at(i)->AP_speed);
			//v = DirectX::XMVectorScale(v, deltaTime);

			//this->m_AIComponents.at(i)->AP_position = DirectX::XMVectorMultiply(v, this->m_AIComponents.at(i)->AP_position);
			this->m_AIComponents.at(i)->AP_position = DirectX::XMVectorAdd(v, this->m_AIComponents.at(i)->AP_position);
		}
	}

	return SUCCESS;
}

void AIHandler::SetComponentActive(int compID)
{
	this->m_AIComponents.at(compID)->AP_active = true;
}

void AIHandler::SetComponentFalse(int compID)
{
	this->m_AIComponents.at(compID)->AP_active = false;
}

void AIHandler::SetEntityID(int compID, int entityID)
{
	this->m_AIComponents.at(compID)->AP_entityID = entityID;
}

void AIHandler::SetTriggered(int compID, bool triggered)
{
	this->m_AIComponents.at(compID)->AP_triggered = triggered;
}

void AIHandler::SetTime(int compID, int time)
{
	this->m_AIComponents.at(compID)->AP_time = time;
}

void AIHandler::SetSpeed(int compID, float speed)
{
	this->m_AIComponents.at(compID)->AP_speed = speed;
}

void AIHandler::SetDirection(int compID, int direction)
{
	this->m_AIComponents.at(compID)->AP_direction = direction;
}

void AIHandler::SetCurrentWaypoint(int compID, int latestWaypoint)
{
	this->m_AIComponents.at(compID)->AP_latestWaypointID = latestWaypoint;
}

void AIHandler::SetPattern(int compID, int pattern)
{
	this->m_AIComponents.at(compID)->AP_pattern = pattern;
}

void AIHandler::SetWaypoints(int compID, DirectX::XMVECTOR waypoints[])
{
	for (int i = 0; i < 8; i++)
	{
		this->m_AIComponents.at(compID)->AP_waypoints[i] = waypoints[i];
		this->m_AIComponents.at(compID)->AP_nrOfWaypoint++;
	}
}

int AIHandler::GetNrOfAIComponents() const
{
	return this->m_nrOfAIComponents;
}

DirectX::XMVECTOR AIHandler::GetPosition(int compID) const
{
	return this->m_AIComponents.at(compID)->AP_position;
}

AIComponent * AIHandler::GetNextAvailableComponents()
{
	// Increase vector by initiating new AIComponents
	if (this->m_nrOfAIComponents == this->m_maxOfAIComponents)
	{
		int oldMax = this->m_maxOfAIComponents;
		this->m_maxOfAIComponents += this->m_maxOfAIComponents;
		for (int i = oldMax; i < this->m_maxOfAIComponents; i++)
		{
			this->m_AIComponents.push_back(CreateAIComponent(i));
		}
	}
	this->m_nrOfAIComponents++;
	return this->m_AIComponents[this->m_nrOfAIComponents - 1];
}

AIComponent* AIHandler::CreateAIComponent(int entityID)
{
	AIComponent* newComponent = nullptr;
	newComponent = new AIComponent;

	newComponent->AP_active = 0;
	newComponent->AP_entityID = entityID;
	newComponent->AP_position = DirectX::XMVECTOR();

	newComponent->AP_triggered = false;
	newComponent->AP_pattern = 0;
	newComponent->AP_time = 0;
	newComponent->AP_speed = 0;
	newComponent->AP_direction = 0;
	newComponent->AP_nextWaypointID = 0;
	newComponent->AP_latestWaypointID = 0;
	newComponent->AP_nrOfWaypoint = 0;

	for (int i = 0; i < 8; i++)
	{
		newComponent->AP_waypoints[i] = DirectX::XMVECTOR();
	}

	return newComponent;
}

bool AIHandler::WaypointApprox(int compID)
{
	int current = this->m_AIComponents.at(compID)->AP_latestWaypointID;
	int next = this->m_AIComponents.at(compID)->AP_nextWaypointID;

	DirectX::XMVECTOR v = DirectX::XMVectorSubtract(this->m_AIComponents.at(compID)->AP_waypoints[next]
		,this->m_AIComponents.at(compID)->AP_position);

	float length = VectorLength(v);

	if (length < 0.1f)
	{
		this->WaypointUpdated = false;
		return true;
	}

	return false;
}

int AIHandler::GetNextWaypoint(int compID, int pattern)
{
	int next = this->m_AIComponents.at(compID)->AP_latestWaypointID;
	int current = this->m_AIComponents.at(compID)->AP_nextWaypointID;

	if (pattern == 1)
	{
		//TODO Linear pattern next waypoint logic
	}
	else
	{

	}

	if (next == current)
	{

	}

	this->m_AIComponents.at(compID)->AP_latestWaypointID;
	this->m_AIComponents.at(compID)->AP_direction;

	return 0;
}

float AIHandler::VectorLength(DirectX::XMVECTOR v)
{
	float length = DirectX::XMVectorGetX(DirectX::XMVector3Length(v));
	return length;
}
<|endoftext|>


<commit_before>#include "AIHandler.h"
#define SUCCESS 1
#define FAIL 0

AIHandler::AIHandler() {}
AIHandler::~AIHandler() {}
int AIHandler::Shutdown()
{
	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		delete this->m_AIComponents[i];
	}

	return SUCCESS;
}

int AIHandler::Initialize(int max)
{
	this->m_nrOfAIComponents = 0;

	if (max <= 0)
	{
		// Don't allow negative or zero initiated components
		max = 2;
	}

	this->m_maxOfAIComponents = max;

	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		this->m_AIComponents.push_back(CreateAIComponent(-1));
	}

	return SUCCESS;
}
int AIHandler::Update(float deltaTime)
{
	for (int i = 0; i < this->m_nrOfAIComponents; i++)
	{
		//TODO: Remove active from this statement
		if (this->m_AIComponents[i]->AC_active && this->m_AIComponents[i]->AC_triggered && this->m_AIComponents[i]->AC_nrOfWaypoint != 0)
		{
			// AIComponent logic/behavior, movement of e.g. platforms
			if (this->m_AIComponents[i]->AC_pattern == AI_ONEWAY)
			{
				//One-way pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_nrOfWaypoint then stop*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;

						if (this->m_AIComponents[i]->AC_nextWaypointID + 1 < this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID++;

						//the platform stops when arriving at its destination
						this->m_AIComponents[i]->AC_triggered = false;

						if (this->m_AIComponents[i]->AC_nextWaypointID == this->m_AIComponents[i]->AC_nrOfWaypoint - 1)
							this->m_AIComponents[i]->AC_direction = 1;
						else if (this->m_AIComponents[i]->AC_nextWaypointID < 0)
							this->m_AIComponents[i]->AC_nextWaypointID = 0;
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;

						if (this->m_AIComponents[i]->AC_nextWaypointID > 0)
							this->m_AIComponents[i]->AC_nextWaypointID--;

						//the platform stops when arriving at its destination
						this->m_AIComponents[i]->AC_triggered = false;

						if (this->m_AIComponents[i]->AC_nextWaypointID == 0)
							this->m_AIComponents[i]->AC_direction = 0;
						else if (this->m_AIComponents[i]->AC_nextWaypointID > this->m_AIComponents[i]->AC_nrOfWaypoint - 1)
							this->m_AIComponents[i]->AC_nextWaypointID = this->m_AIComponents[i]->AC_nrOfWaypoint;
					}
					else
						UpdatePosition(i);
				}
			}
			else if (this->m_AIComponents[i]->AC_pattern == AI_ROUNDTRIP)
			{
				//Round-trip pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_numberOfWaypoint, back to 0 and then stop*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						1.0f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;
						this->m_AIComponents[i]->AC_nextWaypointID++;

						//the platform stops when arriving at its starting location.
						if (this->m_AIComponents[i]->AC_nextWaypointID >= this->m_AIComponents[i]->AC_nrOfWaypoint)
						{
							this->m_AIComponents[i]->AC_nextWaypointID--;
							this->m_AIComponents[i]->AC_direction = 1;
						}
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						1.0f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;
						this->m_AIComponents[i]->AC_nextWaypointID--;

						if (this->m_AIComponents[i]->AC_nextWaypointID < 0)
						{
							//the platform ready to be triggered again
							this->m_AIComponents[i]->AC_direction = 0;
							this->m_AIComponents[i]->AC_nextWaypointID = 0;
							//platform stops when returning to start position
							//this->m_AIComponents[i]->AC_triggered = false;
						}
					}
					else
						UpdatePosition(i);
				}
			}
			else
			{
				//Circular pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_nrOfWaypoints then go to 0*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						1.0f, i))
					{
						this->m_AIComponents[i]->AC_nextWaypointID++;

						if (this->m_AIComponents[i]->AC_nextWaypointID >= this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID = 0;
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						1.0f, i))
					{
						this->m_AIComponents[i]->AC_nextWaypointID--;

						if (this->m_AIComponents[i]->AC_nextWaypointID <= this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID = this->m_AIComponents[i]->AC_nrOfWaypoint;
					}
					else
						UpdatePosition(i);
				}
			}
#ifdef _DEBUG
			if (this->m_AIComponents[i]->AC_pattern == AI_NONE)
			{
				printf("AIHandler::Update - Component %d to Entity %d was called containing AI_NONE pattern\n",
					i, this->m_AIComponents[i]->AC_entityID);
			}
#endif // _DEBUG
		}
	}
	return SUCCESS;
}

AIComponent * AIHandler::GetNextAvailableComponents()
{
	// Increase vector by initiating new AIComponents
	if (this->m_nrOfAIComponents == this->m_maxOfAIComponents)
	{
		int oldMax = this->m_maxOfAIComponents;
		this->m_maxOfAIComponents += this->m_maxOfAIComponents;
		for (int i = oldMax; i < this->m_maxOfAIComponents; i++)
		{
			this->m_AIComponents.push_back(CreateAIComponent(i));
		}
	}
	this->m_nrOfAIComponents++;
	return this->m_AIComponents[this->m_nrOfAIComponents - 1];
}

AIComponent* AIHandler::CreateAIComponent(int entityID)
{
	AIComponent* newComponent = nullptr;
	newComponent = new AIComponent;

	for (int i = 0; i < 8; i++)
	{
		newComponent->AC_waypoints[i] = DirectX::XMVECTOR();
	}

	return newComponent;
}

bool AIHandler::WaypointApprox(DirectX::XMVECTOR c1, DirectX::XMVECTOR c2, float distance, int i)
{
	//Approximation if position of the platform is the same as the nextWaypoint to see if it reached its goal.
	float dx = abs(DirectX::XMVectorGetX(c2) - DirectX::XMVectorGetX(c1));
	float dy = abs(DirectX::XMVectorGetY(c2) - DirectX::XMVectorGetY(c1));
	float dz = abs(DirectX::XMVectorGetZ(c2) - DirectX::XMVectorGetZ(c1));

	if (dx > distance) return false; // too far in x direction
	if (dy > distance) return false; // too far in y direction
	if (dz > distance) return false; // too far in z direction

	this->m_AIComponents[i]->AC_WaypointUpdated = false;

	return true;
}

void AIHandler::UpdatePosition(int i)
{
	//When the platform has reached its destination, the WaypointUpdate is not updated (false). Then the platform is given a new Waypoint.
	if (this->m_AIComponents[i]->AC_WaypointUpdated == false && this->m_AIComponents[i]->AC_triggered)
	{
		this->m_AIComponents[i]->AC_dir = DirectX::XMVector4Normalize(DirectX::XMVectorSubtract(
			this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
			this->m_AIComponents[i]->AC_position));
		this->m_AIComponents[i]->AC_WaypointUpdated = true;
	}
}
<commit_msg>FIX Platform bug<commit_after>#include "AIHandler.h"
#define SUCCESS 1
#define FAIL 0

AIHandler::AIHandler() {}
AIHandler::~AIHandler() {}
int AIHandler::Shutdown()
{
	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		delete this->m_AIComponents[i];
	}

	return SUCCESS;
}

int AIHandler::Initialize(int max)
{
	this->m_nrOfAIComponents = 0;

	if (max <= 0)
	{
		// Don't allow negative or zero initiated components
		max = 2;
	}

	this->m_maxOfAIComponents = max;

	for (int i = 0; i < this->m_maxOfAIComponents; i++)
	{
		this->m_AIComponents.push_back(CreateAIComponent(-1));
	}

	return SUCCESS;
}
int AIHandler::Update(float deltaTime)
{
	for (int i = 0; i < this->m_nrOfAIComponents; i++)
	{
		//TODO: Remove active from this statement
		if (this->m_AIComponents[i]->AC_active == 1 && this->m_AIComponents[i]->AC_triggered && this->m_AIComponents[i]->AC_nrOfWaypoint != 0)
		{
			// AIComponent logic/behavior, movement of e.g. platforms
			if (this->m_AIComponents[i]->AC_pattern == AI_ONEWAY)
			{
				//One-way pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_nrOfWaypoint then stop*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;

						if (this->m_AIComponents[i]->AC_nextWaypointID + 1 < this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID++;

						if (this->m_AIComponents[i]->AC_nextWaypointID == this->m_AIComponents[i]->AC_nrOfWaypoint - 1)
						{
							//the platform stops when arriving at its destination
							this->m_AIComponents[i]->AC_triggered = false;
							this->m_AIComponents[i]->AC_direction = 1;
							this->m_AIComponents[i]->AC_position = this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nrOfWaypoint - 1];
							this->m_AIComponents[i]->AC_nextWaypointID = this->m_AIComponents[i]->AC_nrOfWaypoint - 2;
						}
						else if (this->m_AIComponents[i]->AC_nextWaypointID < 0)
							this->m_AIComponents[i]->AC_nextWaypointID = 0;
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;

						if (this->m_AIComponents[i]->AC_nextWaypointID > 0)
							this->m_AIComponents[i]->AC_nextWaypointID--;

						if (this->m_AIComponents[i]->AC_nextWaypointID == 0)
						{
							//the platform stops when arriving at its destination
							this->m_AIComponents[i]->AC_triggered = false;
							this->m_AIComponents[i]->AC_direction = 0;
							this->m_AIComponents[i]->AC_position = this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nrOfWaypoint - 1];
							this->m_AIComponents[i]->AC_nextWaypointID = 1;
						}
						else if (this->m_AIComponents[i]->AC_nextWaypointID > this->m_AIComponents[i]->AC_nrOfWaypoint - 1)
							this->m_AIComponents[i]->AC_nextWaypointID = this->m_AIComponents[i]->AC_nrOfWaypoint;
					}
					else
						UpdatePosition(i);
				}
			}
			else if (this->m_AIComponents[i]->AC_pattern == AI_ROUNDTRIP)
			{
				//Round-trip pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_numberOfWaypoint, back to 0 and then stop*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;
						this->m_AIComponents[i]->AC_nextWaypointID++;

						if (this->m_AIComponents[i]->AC_nextWaypointID >= this->m_AIComponents[i]->AC_nrOfWaypoint)
						{
							this->m_AIComponents[i]->AC_nextWaypointID--;
							this->m_AIComponents[i]->AC_direction = 1;
						}
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_latestWaypointID = this->m_AIComponents[i]->AC_nextWaypointID;
						this->m_AIComponents[i]->AC_nextWaypointID--;

						if (this->m_AIComponents[i]->AC_nextWaypointID < 0)
						{
							this->m_AIComponents[i]->AC_direction = 0;
							this->m_AIComponents[i]->AC_nextWaypointID = 1;

							//platform stops when returning to start position
							//this->m_AIComponents[i]->AC_triggered = false;
						}
					}
					else
						UpdatePosition(i);
				}
			}
			else if (this->m_AIComponents[i]->AC_pattern == AI_CIRCULAR)
			{
				//Circular pattern
				//default direction 0 assumed in description.
				/*This pattern will move the platform from 0 to AC_nrOfWaypoints then go to 0*/
				if (this->m_AIComponents[i]->AC_direction == 0)
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_nextWaypointID++;

						if (this->m_AIComponents[i]->AC_nextWaypointID >= this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID = 0;
					}
					else
						UpdatePosition(i);
				}
				else
				{
					if (WaypointApprox(
						this->m_AIComponents[i]->AC_position,
						this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
						0.05f, i))
					{
						this->m_AIComponents[i]->AC_nextWaypointID--;

						if (this->m_AIComponents[i]->AC_nextWaypointID <= this->m_AIComponents[i]->AC_nrOfWaypoint)
							this->m_AIComponents[i]->AC_nextWaypointID = this->m_AIComponents[i]->AC_nrOfWaypoint;
					}
					else
						UpdatePosition(i);
				}
			}
#ifdef _DEBUG
			if (this->m_AIComponents[i]->AC_pattern == AI_NONE)
			{
				printf("AIHandler::Update - Component %d to Entity %d was called containing AI_NONE pattern\n",
					i, this->m_AIComponents[i]->AC_entityID);
			}
#endif // _DEBUG
		}
	}
	return SUCCESS;
}

AIComponent * AIHandler::GetNextAvailableComponents()
{
	// Increase vector by initiating new AIComponents
	if (this->m_nrOfAIComponents == this->m_maxOfAIComponents)
	{
		int oldMax = this->m_maxOfAIComponents;
		this->m_maxOfAIComponents += this->m_maxOfAIComponents;
		for (int i = oldMax; i < this->m_maxOfAIComponents; i++)
		{
			this->m_AIComponents.push_back(CreateAIComponent(i));
		}
	}
	this->m_nrOfAIComponents++;
	return this->m_AIComponents[this->m_nrOfAIComponents - 1];
}

AIComponent* AIHandler::CreateAIComponent(int entityID)
{
	AIComponent* newComponent = nullptr;
	newComponent = new AIComponent;

	for (int i = 0; i < 8; i++)
	{
		newComponent->AC_waypoints[i] = DirectX::XMVECTOR();
	}

	return newComponent;
}

bool AIHandler::WaypointApprox(DirectX::XMVECTOR c1, DirectX::XMVECTOR c2, float distance, int i)
{
	//Approximation if position of the platform is the same as the nextWaypoint to see if it reached its goal.
	float dx = abs(DirectX::XMVectorGetX(c2) - DirectX::XMVectorGetX(c1));
	float dy = abs(DirectX::XMVectorGetY(c2) - DirectX::XMVectorGetY(c1));
	float dz = abs(DirectX::XMVectorGetZ(c2) - DirectX::XMVectorGetZ(c1));

	if (dx > distance) return false; // too far in x direction
	if (dy > distance) return false; // too far in y direction
	if (dz > distance) return false; // too far in z direction

	this->m_AIComponents[i]->AC_WaypointUpdated = false;

	return true;
}

void AIHandler::UpdatePosition(int i)
{
	//When the platform has reached its destination, the WaypointUpdate is not updated (false). Then the platform is given a new Waypoint.
	if (this->m_AIComponents[i]->AC_WaypointUpdated == false && this->m_AIComponents[i]->AC_triggered)
	{
		this->m_AIComponents[i]->AC_dir = DirectX::XMVector4Normalize(DirectX::XMVectorSubtract(
			this->m_AIComponents[i]->AC_waypoints[this->m_AIComponents[i]->AC_nextWaypointID],
			this->m_AIComponents[i]->AC_position));
		this->m_AIComponents[i]->AC_WaypointUpdated = true;
	}
}
<|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  03/2017

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TClass.h"
#include "TRegexp.h"

#include "ROOT/TDFInterface.hxx"

#include <vector>
#include <string>
using namespace ROOT::Experimental::TDF;
using namespace ROOT::Internal::TDF;
using namespace ROOT::Detail::TDF;

namespace ROOT {
namespace Experimental {
namespace TDF {
// extern templates
template class TInterface<TLoopManager>;
template class TInterface<TFilterBase>;
template class TInterface<TCustomColumnBase>;
}
}

namespace Internal {
namespace TDF {
// Match expression against names of branches passed as parameter
// Return vector of names of the branches used in the expression
std::vector<std::string> GetUsedBranchesNames(const std::string expression, TObjArray *branches,
                                              const std::vector<std::string> &tmpBranches)
{
   // Check what branches and temporary branches are used in the expression
   // To help matching the regex
   std::string paddedExpr = " " + expression + " ";
   int paddedExprLen = paddedExpr.size();
   static const std::string regexBit("[^a-zA-Z0-9_]");
   std::vector<std::string> usedBranches;
   for (auto brName : tmpBranches) {
      std::string bNameRegexContent = regexBit + brName + regexBit;
      TRegexp bNameRegex(bNameRegexContent.c_str());
      if (-1 != bNameRegex.Index(paddedExpr.c_str(), &paddedExprLen)) {
         usedBranches.emplace_back(brName.c_str());
      }
   }
   if (!branches) return usedBranches;
   for (auto bro : *branches) {
      auto brName = bro->GetName();
      std::string bNameRegexContent = regexBit + brName + regexBit;
      TRegexp bNameRegex(bNameRegexContent.c_str());
      if (-1 != bNameRegex.Index(paddedExpr.c_str(), &paddedExprLen)) {
         usedBranches.emplace_back(brName);
      }
   }
   return usedBranches;
}

// Jit a string filter or a string temporary column, call this->Define or this->Filter as needed
// Return pointer to the new functional chain node returned by the call, cast to Long_t
Long_t JitTransformation(void *thisPtr, const std::string &methodName, const std::string &nodeTypeName,
                         const std::string &name, const std::string &expression, TObjArray *branches,
                         const std::vector<std::string> &tmpBranches,
                         const std::map<std::string, TmpBranchBasePtr_t> &tmpBookedBranches, TTree *tree)
{
   auto usedBranches = GetUsedBranchesNames(expression, branches, tmpBranches);
   auto exprNeedsVariables = !usedBranches.empty();

   // Move to the preparation of the jitting
   // We put all of the jitted entities in a namespace called
   // __tdf_filter_N, where N is a monotonically increasing index.
   TInterpreter::EErrorCode interpErrCode;
   std::vector<std::string> usedBranchesTypes;
   std::stringstream ss;
   static unsigned int iNs = 0U;
   ss << "__tdf_" << iNs++;
   const auto nsName = ss.str();
   ss.str("");

   if (exprNeedsVariables) {
      // Declare a namespace and inside it the variables in the expression
      ss << "namespace " << nsName;
      ss << " {\n";
      for (auto brName : usedBranches) {
         // The map is a const reference, so no operator[]
         auto tmpBrIt = tmpBookedBranches.find(brName);
         auto tmpBr = tmpBrIt == tmpBookedBranches.end() ? nullptr : tmpBrIt->second.get();
         auto brTypeName = ColumnName2ColumnTypeName(brName, tree, tmpBr);
         ss << brTypeName << " " << brName << ";\n";
         usedBranchesTypes.emplace_back(brTypeName);
      }
      ss << "}";
      auto variableDeclarations = ss.str();
      ss.str("");
      // We need ProcessLine to trigger auto{parsing,loading} where needed
      gInterpreter->ProcessLine(variableDeclarations.c_str(), &interpErrCode);
      if (TInterpreter::EErrorCode::kNoError != interpErrCode) {
         std::string msg = "Cannot declare these variables ";
         msg += " ";
         msg += variableDeclarations;
         if (TInterpreter::EErrorCode::kNoError != interpErrCode) {
            msg += "\nInterpreter error code is " + std::to_string(interpErrCode) + ".";
         }
         throw std::runtime_error(msg);
      }
   }

   // Declare within the same namespace, the expression to make sure it
   // is proper C++
   ss << "namespace " << nsName << "{ auto res = " << expression << ";}\n";
   // Headers must have been parsed and libraries loaded: we can use Declare
   if (!gInterpreter->Declare(ss.str().c_str())) {
      std::string msg = "Cannot interpret this expression: ";
      msg += " ";
      msg += ss.str();
      throw std::runtime_error(msg);
   }

   // Now we build the lambda and we invoke the method with it in the jitted world
   ss.str("");
   ss << "[](";
   for (unsigned int i = 0; i < usedBranchesTypes.size(); ++i) {
      // We pass by reference to avoid expensive copies
      ss << usedBranchesTypes[i] << "& " << usedBranches[i] << ", ";
   }
   if (!usedBranchesTypes.empty()) ss.seekp(-2, ss.cur);
   ss << "){ return " << expression << ";}";
   auto filterLambda = ss.str();

   // Here we have two cases: filter and column
   ss.str("");
   ss << "((" << nodeTypeName << "*)" << thisPtr << ")->" << methodName << "(";
   if (methodName == "Define") {
      ss << "\"" << name << "\", ";
   }
   ss << filterLambda << ", {";
   for (auto brName : usedBranches) {
      ss << "\"" << brName << "\", ";
   }
   if (exprNeedsVariables) ss.seekp(-2, ss.cur); // remove the last ",
   ss << "}";

   if (methodName == "Filter") {
      ss << ", \"" << name << "\"";
   }

   ss << ");";

   auto retVal = gInterpreter->ProcessLine(ss.str().c_str(), &interpErrCode);
   if (TInterpreter::EErrorCode::kNoError != interpErrCode || !retVal) {
      std::string msg = "Cannot interpret the invocation to " + methodName + ": ";
      msg += " ";
      msg += ss.str();
      if (TInterpreter::EErrorCode::kNoError != interpErrCode) {
         msg += "\nInterpreter error code is " + std::to_string(interpErrCode) + ".";
      }
      throw std::runtime_error(msg);
   }
   return retVal;
}

// Jit and call something equivalent to "this->BuildAndBook<BranchTypes...>(params...)"
// (see comments in the body for actual jitted code)
void JitBuildAndBook(const ColumnNames_t &bl, const std::string &nodeTypename, void *thisPtr, const std::type_info &art,
                     const std::type_info &at, const void *r, TTree *tree, unsigned int nSlots,
                     const std::map<std::string, TmpBranchBasePtr_t> &tmpBranches)
{
   gInterpreter->ProcessLine("#include \"ROOT/TDataFrame.hxx\"");
   auto nBranches = bl.size();

   // retrieve pointers to temporary columns (null if the column is not temporary)
   std::vector<TCustomColumnBase *> tmpBranchPtrs(nBranches, nullptr);
   for (auto i = 0u; i < nBranches; ++i) {
      auto tmpBranchIt = tmpBranches.find(bl[i]);
      if (tmpBranchIt != tmpBranches.end()) tmpBranchPtrs[i] = tmpBranchIt->second.get();
   }

   // retrieve branch type names as strings
   std::vector<std::string> branchTypeNames(nBranches);
   for (auto i = 0u; i < nBranches; ++i) {
      const auto branchTypeName = ColumnName2ColumnTypeName(bl[i], tree, tmpBranchPtrs[i]);
      if (branchTypeName.empty()) {
         std::string exceptionText = "The type of column ";
         exceptionText += bl[i];
         exceptionText += " could not be guessed. Please specify one.";
         throw std::runtime_error(exceptionText.c_str());
      }
      branchTypeNames[i] = branchTypeName;
   }

   // retrieve type of result of the action as a string
   auto actionResultTypeClass = TClass::GetClass(art);
   if (!actionResultTypeClass) {
      std::string exceptionText = "An error occurred while inferring the result type of an operation.";
      throw std::runtime_error(exceptionText.c_str());
   }
   const auto actionResultTypeName = actionResultTypeClass->GetName();

   // retrieve type of action as a string
   auto actionTypeClass = TClass::GetClass(at);
   if (!actionTypeClass) {
      std::string exceptionText = "An error occurred while inferring the action type of the operation.";
      throw std::runtime_error(exceptionText.c_str());
   }
   const auto actionTypeName = actionTypeClass->GetName();

   // createAction_str will contain the following:
   // ROOT::Internal::TDF::CallBuildAndBook<nodeType, actionType, branchType1, branchType2...>(
   //    reinterpret_cast<nodeType*>(thisPtr), *reinterpret_cast<ROOT::ColumnNames_t*>(&bl),
   //    *reinterpret_cast<actionResultType*>(r), reinterpret_cast<ActionType*>(nullptr))
   std::stringstream createAction_str;
   createAction_str << "ROOT::Internal::TDF::CallBuildAndBook<" << nodeTypename << ", " << actionTypeName;
   for (auto &branchTypeName : branchTypeNames) createAction_str << ", " << branchTypeName;
   createAction_str << ">("
                    << "reinterpret_cast<" << nodeTypename << "*>(" << thisPtr << "), "
                    << "*reinterpret_cast<ROOT::Detail::TDF::ColumnNames_t*>(" << &bl << "), " << nSlots
                    << ", *reinterpret_cast<" << actionResultTypeName << "*>(" << r << "));";
   auto error = TInterpreter::EErrorCode::kNoError;
   gInterpreter->ProcessLine(createAction_str.str().c_str(), &error);
   if (error) {
      std::string exceptionText = "An error occurred while jitting this action:\n";
      exceptionText += createAction_str.str();
      throw std::runtime_error(exceptionText.c_str());
   }
}
} // end ns TDF
} // end ns Internal
} // end ns ROOT
<commit_msg>[TDF] Minor refactoring of error handling in JitTranformation<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  03/2017

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TClass.h"
#include "TRegexp.h"

#include "ROOT/TDFInterface.hxx"

#include <vector>
#include <string>
using namespace ROOT::Experimental::TDF;
using namespace ROOT::Internal::TDF;
using namespace ROOT::Detail::TDF;

namespace ROOT {
namespace Experimental {
namespace TDF {
// extern templates
template class TInterface<TLoopManager>;
template class TInterface<TFilterBase>;
template class TInterface<TCustomColumnBase>;
}
}

namespace Internal {
namespace TDF {
// Match expression against names of branches passed as parameter
// Return vector of names of the branches used in the expression
std::vector<std::string> GetUsedBranchesNames(const std::string expression, TObjArray *branches,
                                              const std::vector<std::string> &tmpBranches)
{
   // Check what branches and temporary branches are used in the expression
   // To help matching the regex
   std::string paddedExpr = " " + expression + " ";
   int paddedExprLen = paddedExpr.size();
   static const std::string regexBit("[^a-zA-Z0-9_]");
   std::vector<std::string> usedBranches;
   for (auto brName : tmpBranches) {
      std::string bNameRegexContent = regexBit + brName + regexBit;
      TRegexp bNameRegex(bNameRegexContent.c_str());
      if (-1 != bNameRegex.Index(paddedExpr.c_str(), &paddedExprLen)) {
         usedBranches.emplace_back(brName.c_str());
      }
   }
   if (!branches) return usedBranches;
   for (auto bro : *branches) {
      auto brName = bro->GetName();
      std::string bNameRegexContent = regexBit + brName + regexBit;
      TRegexp bNameRegex(bNameRegexContent.c_str());
      if (-1 != bNameRegex.Index(paddedExpr.c_str(), &paddedExprLen)) {
         usedBranches.emplace_back(brName);
      }
   }
   return usedBranches;
}

// Jit a string filter or a string temporary column, call this->Define or this->Filter as needed
// Return pointer to the new functional chain node returned by the call, cast to Long_t
Long_t JitTransformation(void *thisPtr, const std::string &methodName, const std::string &nodeTypeName,
                         const std::string &name, const std::string &expression, TObjArray *branches,
                         const std::vector<std::string> &tmpBranches,
                         const std::map<std::string, TmpBranchBasePtr_t> &tmpBookedBranches, TTree *tree)
{
   auto usedBranches = GetUsedBranchesNames(expression, branches, tmpBranches);
   auto exprNeedsVariables = !usedBranches.empty();

   // Move to the preparation of the jitting
   // We put all of the jitted entities in a namespace called
   // __tdf_filter_N, where N is a monotonically increasing index.
   std::vector<std::string> usedBranchesTypes;
   std::stringstream ss;
   static unsigned int iNs = 0U;
   ss << "__tdf_" << iNs++;
   const auto nsName = ss.str();
   ss.str("");

   if (exprNeedsVariables) {
      // Declare a namespace and inside it the variables in the expression
      ss << "namespace " << nsName;
      ss << " {\n";
      for (auto brName : usedBranches) {
         // The map is a const reference, so no operator[]
         auto tmpBrIt = tmpBookedBranches.find(brName);
         auto tmpBr = tmpBrIt == tmpBookedBranches.end() ? nullptr : tmpBrIt->second.get();
         auto brTypeName = ColumnName2ColumnTypeName(brName, tree, tmpBr);
         ss << brTypeName << " " << brName << ";\n";
         usedBranchesTypes.emplace_back(brTypeName);
      }
      ss << "}";
      auto variableDeclarations = ss.str();
      ss.str("");
      // We need ProcessLine to trigger auto{parsing,loading} where needed
      TInterpreter::EErrorCode interpErrCode;
      gInterpreter->ProcessLine(variableDeclarations.c_str(), &interpErrCode);
      if (TInterpreter::EErrorCode::kNoError != interpErrCode) {
         std::string msg = "Cannot declare these variables:  ";
         msg += variableDeclarations;
         msg += "\nInterpreter error code is " + std::to_string(interpErrCode) + ".";
         throw std::runtime_error(msg);
      }
   }

   // Declare within the same namespace, the expression to make sure it
   // is proper C++
   ss << "namespace " << nsName << "{ auto res = " << expression << ";}\n";
   // Headers must have been parsed and libraries loaded: we can use Declare
   if (!gInterpreter->Declare(ss.str().c_str())) {
      std::string msg = "Cannot interpret this expression: ";
      msg += " ";
      msg += ss.str();
      throw std::runtime_error(msg);
   }

   // Now we build the lambda and we invoke the method with it in the jitted world
   ss.str("");
   ss << "[](";
   for (unsigned int i = 0; i < usedBranchesTypes.size(); ++i) {
      // We pass by reference to avoid expensive copies
      ss << usedBranchesTypes[i] << "& " << usedBranches[i] << ", ";
   }
   if (!usedBranchesTypes.empty()) ss.seekp(-2, ss.cur);
   ss << "){ return " << expression << ";}";
   auto filterLambda = ss.str();

   // Here we have two cases: filter and column
   ss.str("");
   ss << "((" << nodeTypeName << "*)" << thisPtr << ")->" << methodName << "(";
   if (methodName == "Define") {
      ss << "\"" << name << "\", ";
   }
   ss << filterLambda << ", {";
   for (auto brName : usedBranches) {
      ss << "\"" << brName << "\", ";
   }
   if (exprNeedsVariables) ss.seekp(-2, ss.cur); // remove the last ",
   ss << "}";

   if (methodName == "Filter") {
      ss << ", \"" << name << "\"";
   }

   ss << ");";

   TInterpreter::EErrorCode interpErrCode;
   auto retVal = gInterpreter->ProcessLine(ss.str().c_str(), &interpErrCode);
   if (TInterpreter::EErrorCode::kNoError != interpErrCode || !retVal) {
      std::string msg = "Cannot interpret the invocation to " + methodName + ":  ";
      msg += ss.str();
      if (TInterpreter::EErrorCode::kNoError != interpErrCode) {
         msg += "\nInterpreter error code is " + std::to_string(interpErrCode) + ".";
      }
      throw std::runtime_error(msg);
   }
   return retVal;
}

// Jit and call something equivalent to "this->BuildAndBook<BranchTypes...>(params...)"
// (see comments in the body for actual jitted code)
void JitBuildAndBook(const ColumnNames_t &bl, const std::string &nodeTypename, void *thisPtr, const std::type_info &art,
                     const std::type_info &at, const void *r, TTree *tree, unsigned int nSlots,
                     const std::map<std::string, TmpBranchBasePtr_t> &tmpBranches)
{
   gInterpreter->ProcessLine("#include \"ROOT/TDataFrame.hxx\"");
   auto nBranches = bl.size();

   // retrieve pointers to temporary columns (null if the column is not temporary)
   std::vector<TCustomColumnBase *> tmpBranchPtrs(nBranches, nullptr);
   for (auto i = 0u; i < nBranches; ++i) {
      auto tmpBranchIt = tmpBranches.find(bl[i]);
      if (tmpBranchIt != tmpBranches.end()) tmpBranchPtrs[i] = tmpBranchIt->second.get();
   }

   // retrieve branch type names as strings
   std::vector<std::string> branchTypeNames(nBranches);
   for (auto i = 0u; i < nBranches; ++i) {
      const auto branchTypeName = ColumnName2ColumnTypeName(bl[i], tree, tmpBranchPtrs[i]);
      if (branchTypeName.empty()) {
         std::string exceptionText = "The type of column ";
         exceptionText += bl[i];
         exceptionText += " could not be guessed. Please specify one.";
         throw std::runtime_error(exceptionText.c_str());
      }
      branchTypeNames[i] = branchTypeName;
   }

   // retrieve type of result of the action as a string
   auto actionResultTypeClass = TClass::GetClass(art);
   if (!actionResultTypeClass) {
      std::string exceptionText = "An error occurred while inferring the result type of an operation.";
      throw std::runtime_error(exceptionText.c_str());
   }
   const auto actionResultTypeName = actionResultTypeClass->GetName();

   // retrieve type of action as a string
   auto actionTypeClass = TClass::GetClass(at);
   if (!actionTypeClass) {
      std::string exceptionText = "An error occurred while inferring the action type of the operation.";
      throw std::runtime_error(exceptionText.c_str());
   }
   const auto actionTypeName = actionTypeClass->GetName();

   // createAction_str will contain the following:
   // ROOT::Internal::TDF::CallBuildAndBook<nodeType, actionType, branchType1, branchType2...>(
   //    reinterpret_cast<nodeType*>(thisPtr), *reinterpret_cast<ROOT::ColumnNames_t*>(&bl),
   //    *reinterpret_cast<actionResultType*>(r), reinterpret_cast<ActionType*>(nullptr))
   std::stringstream createAction_str;
   createAction_str << "ROOT::Internal::TDF::CallBuildAndBook<" << nodeTypename << ", " << actionTypeName;
   for (auto &branchTypeName : branchTypeNames) createAction_str << ", " << branchTypeName;
   createAction_str << ">("
                    << "reinterpret_cast<" << nodeTypename << "*>(" << thisPtr << "), "
                    << "*reinterpret_cast<ROOT::Detail::TDF::ColumnNames_t*>(" << &bl << "), " << nSlots
                    << ", *reinterpret_cast<" << actionResultTypeName << "*>(" << r << "));";
   auto error = TInterpreter::EErrorCode::kNoError;
   gInterpreter->ProcessLine(createAction_str.str().c_str(), &error);
   if (error) {
      std::string exceptionText = "An error occurred while jitting this action:\n";
      exceptionText += createAction_str.str();
      throw std::runtime_error(exceptionText.c_str());
   }
}
} // end ns TDF
} // end ns Internal
} // end ns ROOT
<|endoftext|>


<commit_before>#include "GroupChat.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(lcServerGroupChat, "telegram.server.groupchat", QtWarningMsg)

namespace Telegram {

namespace Server {

LocalGroupChat::LocalGroupChat(quint32 chatId, quint32 dcId)
{
    m_id = chatId;
    m_dcId = dcId;
}

void LocalGroupChat::setDate(quint32 date)
{
    m_date = date;
}

void LocalGroupChat::setTitle(const QString &title)
{
    m_title = title;
}

void LocalGroupChat::setCreator(quint32 creatorId)
{
    if (!m_members.isEmpty()) {
        qWarning(lcServerGroupChat) << "Invalid setCreator() call for group" << m_id;
        return;
    }
    ChatMember creator;
    creator.userId = creatorId;
    creator.role = ChatMember::Role::Creator;
    m_members.append(creator);
}

void LocalGroupChat::inviteMembers(const QVector<quint32> &members, quint32 inviterId, quint32 date)
{
    for (quint32 userId : members) {
        ChatMember member;
        member.userId = userId;
        member.inviterId = inviterId;
        member.date = date;
        member.role = ChatMember::Role::User;

        m_members.append(member);
    }
}

quint32 GroupChat::creatorId() const
{
    if (m_members.isEmpty()) {
        qWarning(lcServerGroupChat) << "Invalid creatorId() call for group" << m_id;
        return 0;
    }
    return m_members.first().userId;
}

QVector<quint32> GroupChat::memberIds() const
{
    QVector<quint32> ids;
    ids.reserve(m_members.count());
    for (const ChatMember &member : m_members) {
        ids.append(member.userId);
    }

    return ids;
}

} // Server namespace

} // Telegram namespace
<commit_msg>Server/LocalGroupChat: Validate members on invite<commit_after>#include "GroupChat.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(lcServerGroupChat, "telegram.server.groupchat", QtWarningMsg)

namespace Telegram {

namespace Server {

LocalGroupChat::LocalGroupChat(quint32 chatId, quint32 dcId)
{
    m_id = chatId;
    m_dcId = dcId;
}

void LocalGroupChat::setDate(quint32 date)
{
    m_date = date;
}

void LocalGroupChat::setTitle(const QString &title)
{
    m_title = title;
}

void LocalGroupChat::setCreator(quint32 creatorId)
{
    if (!m_members.isEmpty()) {
        qWarning(lcServerGroupChat) << "Invalid setCreator() call for group" << m_id;
        return;
    }
    ChatMember creator;
    creator.userId = creatorId;
    creator.role = ChatMember::Role::Creator;
    m_members.append(creator);
}

void LocalGroupChat::inviteMembers(const QVector<quint32> &members, quint32 inviterId, quint32 date)
{
    QVector<quint32> currentMembers = memberIds();
    for (quint32 userId : members) {
        if (currentMembers.contains(userId)) {
            qWarning(lcServerGroupChat) << "Unable to invite an already active member"
                                        << userId << "of group" << m_id;
            continue;
        }
        ChatMember member;
        member.userId = userId;
        member.inviterId = inviterId;
        member.date = date;
        member.role = ChatMember::Role::User;

        m_members.append(member);
    }
}

quint32 GroupChat::creatorId() const
{
    if (m_members.isEmpty()) {
        qWarning(lcServerGroupChat) << "Invalid creatorId() call for group" << m_id;
        return 0;
    }
    return m_members.first().userId;
}

QVector<quint32> GroupChat::memberIds() const
{
    QVector<quint32> ids;
    ids.reserve(m_members.count());
    for (const ChatMember &member : m_members) {
        ids.append(member.userId);
    }

    return ids;
}

} // Server namespace

} // Telegram namespace
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "rdostudiooutput.h"
#include "rdostudioapp.h"
#include "rdostudiomainfrm.h"
#include "rdo_edit/rdoeditorsciedit.h"
#include "rdo_edit/rdoeditorscilog.h"
#include "rdo_edit/rdoeditoredit.h"
#include "./rdo_tracer/rdotracertrace.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using namespace rdoEditor;

// ----------------------------------------------------------------------------
// ---------- RDOStudioOutput
// ----------------------------------------------------------------------------
BEGIN_MESSAGE_MAP(RDOStudioOutput, RDOStudioDockWnd)
	//{{AFX_MSG_MAP(RDOStudioOutput)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

RDOStudioOutput::RDOStudioOutput()
{
}

RDOStudioOutput::~RDOStudioOutput()
{
	RDOStudioApp::eraseMenu( &popupMenu );
}

int RDOStudioOutput::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (RDOStudioDockWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	tab.Create( NULL, NULL, 0, CRect(0, 0, 100, 100), this, -1 );
	tab.modifyTabStyle( 0, TCS_BOTTOM | TCS_MULTILINE );

	popupMenu.CreatePopupMenu();

	CMenu* mainMenu = AfxGetMainWnd()->GetMenu();

	BOOL maximized;
	studioApp.mainFrame->MDIGetActive( &maximized );
	int delta = maximized ? 1 : 0;

	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 4, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 8, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 10, &popupMenu );
	popupMenu.AppendMenu( MF_SEPARATOR );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 0, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 1, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 2, &popupMenu );
	popupMenu.AppendMenu( MF_SEPARATOR );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 5, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 6, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 7, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 8, &popupMenu );

	build   = new RDOEditorSciLog;
	debug   = new RDOEditorSciEdit;
	tracer  = (CWnd*)::trace.createLog();
	results = new RDOEditorEdit;
	find    = new RDOEditorSciLog;

	build->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	debug->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	tracer->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	results->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	find->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );

	buildStyle.init( "buildStyle" );
	buildStyle.window->showHorzScrollBar = false;
	buildStyle.window->wordWrap          = true;
	buildStyle.load();
	build->setEditorStyle( &buildStyle );
	build->setReadOnly( true );
	build->setPopupMenu( &popupMenu );

	debugStyle.init( "debugStyle" );
	debugStyle.window->showHorzScrollBar = false;
	debugStyle.window->wordWrap          = true;
	debugStyle.load();
	debug->setEditorStyle( &debugStyle );
	debug->setReadOnly( true );
	debug->setPopupMenu( &popupMenu );

	resultsStyle.init( "resultsStyle" );
	resultsStyle.window->showHorzScrollBar = false;
	resultsStyle.window->wordWrap          = true;
	resultsStyle.load();
	results->setEditorStyle( &resultsStyle );
	results->setViewMargin( false );
	results->setViewFoldMargin( false );
	results->setReadOnly( true );
	results->setPopupMenu( &popupMenu );

	findStyle.init( "findStyle" );
	findStyle.window->showHorzScrollBar = false;
	findStyle.window->wordWrap          = true;
	findStyle.load();
	find->setEditorStyle( &findStyle );
	find->setReadOnly( true );
	find->setPopupMenu( &popupMenu );

	tab.insertItem( build, "Build" );
	tab.insertItem( debug, "Debug" );
	tab.insertItem( tracer, "Tracer" );
	tab.insertItem( results, "Results" );
	tab.insertItem( find, "Find in Model" );

	return 0;
}

BOOL RDOStudioOutput::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if ( tab.OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) ) return TRUE;
	return RDOStudioDockWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

void RDOStudioOutput::showBuild()
{
	build->SetFocus();
}

void RDOStudioOutput::showDebug()
{
	debug->SetFocus();
}

void RDOStudioOutput::showTracer()
{
	tab.setCurrentItem( 2 );
	tracer->SetFocus();
}

void RDOStudioOutput::showResults()
{
	results->SetFocus();
}

void RDOStudioOutput::showFind()
{
	find->SetFocus();
}

void RDOStudioOutput::clearBuild()
{
	build->clearAll();
}

void RDOStudioOutput::clearDebug()
{
	debug->clearAll();
}

void RDOStudioOutput::clearResults()
{
	results->clearAll();
}

void RDOStudioOutput::clearFind()
{
	find->clearAll();
}

void RDOStudioOutput::appendString( const RDOEditorSciEdit* const edit, const string& str ) const
{
	bool readOnly = edit->isReadOnly();
	if ( readOnly ) {
		edit->setReadOnly( false );
	}
	bool scroll = edit->isLineVisible( edit->getLineCount() - 1 );
	edit->appendText( str );
	if ( scroll ) {
		int line = edit->getLineCount();
		int line_to_scroll = line > 0 ? line - 1 : 0;
		edit->scrollToLine( line_to_scroll );
		edit->setCurrentPos( edit->getLength() );
	}
	if ( readOnly ) {
		edit->setReadOnly( true );
	}
}

void RDOStudioOutput::appendStringToBuild( const string& str ) const
{
	appendString( build, str );
}

void RDOStudioOutput::appendStringToDebug( const string& str ) const
{
	appendString( debug, str );
}

void RDOStudioOutput::appendStringToFind( const string& str ) const
{
	appendString( find, str );
}
<commit_msg>popupmenu bug fixed<commit_after>#include "stdafx.h"
#include "rdostudiooutput.h"
#include "rdostudioapp.h"
#include "rdostudiomainfrm.h"
#include "rdo_edit/rdoeditorsciedit.h"
#include "rdo_edit/rdoeditorscilog.h"
#include "rdo_edit/rdoeditoredit.h"
#include "./rdo_tracer/rdotracertrace.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using namespace rdoEditor;

// ----------------------------------------------------------------------------
// ---------- RDOStudioOutput
// ----------------------------------------------------------------------------
BEGIN_MESSAGE_MAP(RDOStudioOutput, RDOStudioDockWnd)
	//{{AFX_MSG_MAP(RDOStudioOutput)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

RDOStudioOutput::RDOStudioOutput()
{
}

RDOStudioOutput::~RDOStudioOutput()
{
	RDOStudioApp::eraseMenu( &popupMenu );
}

int RDOStudioOutput::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (RDOStudioDockWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	tab.Create( NULL, NULL, 0, CRect(0, 0, 100, 100), this, -1 );
	tab.modifyTabStyle( 0, TCS_BOTTOM | TCS_MULTILINE );

	popupMenu.CreatePopupMenu();

	CMenu* mainMenu = AfxGetMainWnd()->GetMenu();

	BOOL maximized;
	studioApp.mainFrame->MDIGetActive( &maximized );
	int delta = maximized ? 1 : 0;

	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 4, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 8, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 1 + delta ), 10, &popupMenu );
	popupMenu.AppendMenu( MF_SEPARATOR );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 0, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 1, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 2, &popupMenu );
	popupMenu.AppendMenu( MF_SEPARATOR );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 7, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 8, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 9, &popupMenu );
	RDOStudioApp::appendMenu( mainMenu->GetSubMenu( 2 + delta ), 10, &popupMenu );

	build   = new RDOEditorSciLog;
	debug   = new RDOEditorSciEdit;
	tracer  = (CWnd*)::trace.createLog();
	results = new RDOEditorEdit;
	find    = new RDOEditorSciLog;

	build->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	debug->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	tracer->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	results->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );
	find->Create( NULL, NULL, 0, CRect(0, 0, 0, 0), tab.getTabAsParent(), -1 );

	buildStyle.init( "buildStyle" );
	buildStyle.window->showHorzScrollBar = false;
	buildStyle.window->wordWrap          = true;
	buildStyle.load();
	build->setEditorStyle( &buildStyle );
	build->setReadOnly( true );
	build->setPopupMenu( &popupMenu );

	debugStyle.init( "debugStyle" );
	debugStyle.window->showHorzScrollBar = false;
	debugStyle.window->wordWrap          = true;
	debugStyle.load();
	debug->setEditorStyle( &debugStyle );
	debug->setReadOnly( true );
	debug->setPopupMenu( &popupMenu );

	resultsStyle.init( "resultsStyle" );
	resultsStyle.window->showHorzScrollBar = false;
	resultsStyle.window->wordWrap          = true;
	resultsStyle.load();
	results->setEditorStyle( &resultsStyle );
	results->setViewMargin( false );
	results->setViewFoldMargin( false );
	results->setReadOnly( true );
	results->setPopupMenu( &popupMenu );

	findStyle.init( "findStyle" );
	findStyle.window->showHorzScrollBar = false;
	findStyle.window->wordWrap          = true;
	findStyle.load();
	find->setEditorStyle( &findStyle );
	find->setReadOnly( true );
	find->setPopupMenu( &popupMenu );

	tab.insertItem( build, "Build" );
	tab.insertItem( debug, "Debug" );
	tab.insertItem( tracer, "Tracer" );
	tab.insertItem( results, "Results" );
	tab.insertItem( find, "Find in Model" );

	return 0;
}

BOOL RDOStudioOutput::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if ( tab.OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) ) return TRUE;
	return RDOStudioDockWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

void RDOStudioOutput::showBuild()
{
	build->SetFocus();
}

void RDOStudioOutput::showDebug()
{
	debug->SetFocus();
}

void RDOStudioOutput::showTracer()
{
	tab.setCurrentItem( 2 );
	tracer->SetFocus();
}

void RDOStudioOutput::showResults()
{
	results->SetFocus();
}

void RDOStudioOutput::showFind()
{
	find->SetFocus();
}

void RDOStudioOutput::clearBuild()
{
	build->clearAll();
}

void RDOStudioOutput::clearDebug()
{
	debug->clearAll();
}

void RDOStudioOutput::clearResults()
{
	results->clearAll();
}

void RDOStudioOutput::clearFind()
{
	find->clearAll();
}

void RDOStudioOutput::appendString( const RDOEditorSciEdit* const edit, const string& str ) const
{
	bool readOnly = edit->isReadOnly();
	if ( readOnly ) {
		edit->setReadOnly( false );
	}
	bool scroll = edit->isLineVisible( edit->getLineCount() - 1 );
	edit->appendText( str );
	if ( scroll ) {
		int line = edit->getLineCount();
		int line_to_scroll = line > 0 ? line - 1 : 0;
		edit->scrollToLine( line_to_scroll );
		edit->setCurrentPos( edit->getLength() );
	}
	if ( readOnly ) {
		edit->setReadOnly( true );
	}
}

void RDOStudioOutput::appendStringToBuild( const string& str ) const
{
	appendString( build, str );
}

void RDOStudioOutput::appendStringToDebug( const string& str ) const
{
	appendString( debug, str );
}

void RDOStudioOutput::appendStringToFind( const string& str ) const
{
	appendString( find, str );
}
<|endoftext|>


<commit_before>#include "arena.h"
#include "image_util.h"
#include "image_writer.h"
#include "logger.h"

#include <fstream>

using namespace wotreplay;

const int element_size = 48;

image_writer_t::image_writer_t()
    : filter([](const packet_t &){ return true; }),
      image_width(512), image_height(512)
{}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, int x, int y, int mask) {
    const size_t *shape = element.shape();
    const size_t *image_size = base.shape();
    for (int i = 0; i < shape[0]; ++i) {
        for (int j = 0; j < shape[1]; ++j) {
            // don't touch alpha channel, use from original
            for (int k = 0; k < 3; ++k) {
                if (((i + y) >= image_size[0]) || ((j + x) >= image_size[1])) {
                    continue;
                }
                base[i + y][j + x][k] = mix(base[i + y][j + x][k], base[i + y][j + x][k], (255 - element[i][j][3]) / 255.f,
                                    element[i][j][k] & ((mask >> ((4- (k + 1))*8)) & 0xFF), element[i][j][3] / 255.f);
            }
        }
    }
}

boost::multi_array<uint8_t, 3> image_writer_t::get_element(const std::string &name) {
    boost::multi_array<uint8_t, 3> element, resized_element;
    std::ifstream is("elements/" + name + ".png", std::ios::binary);
    read_png(is, element);
    double f = image_width / 512.0; // we need to scale the elements to the right size
    resize(element, element_size*f, element_size*f, resized_element);
    return resized_element;
}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, std::tuple<float, float> position, int mask) {
    auto shape = base.shape();
    auto element_shape = element.shape();
    float x,y;
    auto position3d = std::make_tuple(std::get<0>(position), 0.f, std::get<1>(position));
    std::tie(x,y) = get_2d_coord(position3d, arena.bounding_box, (int) shape[1], (int) shape[0]);
    draw_element(element, x - element_shape[1]/2, y - element_shape[0]/2, mask);
}

void image_writer_t::draw_grid(boost::multi_array<uint8_t, 3> &image) {
    const int grid_line_width = 2;
    const int grid_cells = 10;
    auto shape = image.shape();
    int grid_width = ((int) shape[1] - (grid_cells + 1) * grid_line_width) / grid_cells;
    int grid_height = ((int) shape[0] - (grid_cells + 1) * grid_line_width) / grid_cells;
    for (int y = 0; y < shape[0]; y += (grid_height + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int x = 0; x < shape[1]; ++x) {
                for (int c = 0; c < 3; ++ c) {
                    image[y + i][x][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
    for (int x = 0; x < shape[1]; x += (grid_width + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int y = 0; y < shape[0]; ++y) {
                for (int c = 0; c < 3; ++ c) {
                    image[y][x + i][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
}

void image_writer_t::draw_elements() {
    auto it = arena.configurations.find(game_mode);
    if (it == arena.configurations.end()) {
        wotreplay::logger.writef(log_level_t::warning, "Could not find configuration for game mode '%1%'\n", game_mode);
        return;
    }

    const arena_configuration_t &configuration = arena.configurations[game_mode];
    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;

    if (game_mode == "domination") {
        auto neutral_base = get_element("neutral_base");
        draw_element(neutral_base, configuration.control_point);
    }

    auto friendly_base = get_element("friendly_base");
    auto enemy_base = get_element("enemy_base");
    for(const auto &entry : configuration.team_base_positions) {
        for (const auto &position : entry.second) {
            draw_element((entry.first - 1) == reference_team_id ? friendly_base : enemy_base, position);
        }
    }

    std::vector<boost::multi_array<uint8_t, 3>> spawns{
        get_element("neutral_spawn1"),
        get_element("neutral_spawn2"),
        get_element("neutral_spawn3"),
        get_element("neutral_spawn4")
    };

    for(const auto &entry : configuration.team_spawn_points) {
        for (int i = 0; i < entry.second.size(); ++i) {
            int mask = (reference_team_id == (entry.first - 1)) ? 0x00FF00FF : 0xFF0000FF;
            draw_element(spawns[i], entry.second[i], mask);
        }
    }

    draw_grid(base);
}

void image_writer_t::draw_death(const packet_t &packet, const game_t &game) {
    uint32_t killer, killed;
    std::tie(killed, killer) = packet.tank_destroyed();
    packet_t position_packet;
    bool found = game.find_property(packet.clock(), killed, property_t::position, position_packet);
    if (found) {
        draw_position(position_packet, game, this->deaths);
    }
}

void image_writer_t::draw_position(const packet_t &packet, const game_t &game, boost::multi_array<float, 3> &image) {
    uint32_t player_id = packet.player_id();

    int team_id = game.get_team_id(player_id);
    if (team_id < 0) return;

    auto shape = image.shape();
    int height = static_cast<int>(shape[1]);
    int width = static_cast<int>(shape[2]);

    const bounding_box_t &bounding_box = game.get_arena().bounding_box;
    std::tuple<float, float> position = get_2d_coord( packet.position(), bounding_box, width, height);
    long x = std::lround(std::get<0>(position));
    long y = std::lround(std::get<1>(position));
    if (x >= 0 && y >= 0 && x < width && y < height) {
        image[team_id][y][x]++;
        if (player_id == game.get_recorder_id()) {
            image[2][y][x]++;
        }
    }
}

void image_writer_t::update(const game_t &game) {
    recorder_team = game.get_team_id(game.get_recorder_id());

    std::set<int> dead_players;
    for (const packet_t &packet : game.get_packets()) {
        if (!filter(packet)) continue;
        if (packet.has_property(property_t::position)
            && dead_players.find(packet.player_id()) == dead_players.end()) {
            draw_position(packet, game, this->positions);
        } else if (packet.has_property(property_t::tank_destroyed)) {
            uint32_t target, killer;
            std::tie(target, killer) = packet.tank_destroyed();
            dead_players.insert(target);
            draw_death(packet, game);
        }
    }
}

void image_writer_t::load_base_map(const std::string &path) {
    boost::multi_array<uint8_t, 3> map;
    std::ifstream is(path, std::ios::binary);
    read_png(is, map);
    resize(map, image_width, image_height, this->base);
}

void image_writer_t::write(std::ostream &os) {
    write_png(os, result);
}

void image_writer_t::init(const arena_t &arena, const std::string &mode) {
    this->arena = arena;
    this->game_mode = mode;

    positions.resize(boost::extents[3][image_height][image_width]);
    deaths.resize(boost::extents[3][image_height][image_width]);

    clear();

    initialized = true;
}

void image_writer_t::clear() {
    std::fill(result.origin(), result.origin() + result.num_elements(), 0.f);
    std::fill(deaths.origin(), deaths.origin() + deaths.num_elements(), 0.f);
    std::fill(positions.origin(), positions.origin() + positions.num_elements(), 0.f);
}

void image_writer_t::finish() {
    draw_basemap();

    const size_t *shape = base.shape();
    result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
    result = base;

    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;
    for (int i = 0; i < image_height; ++i) {
        for (int j = 0; j < image_width; ++j) {
            if (positions[0][i][j] > positions[1][i][j]) {
                // position claimed by first team
                if (reference_team_id == 0) {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                }

            } else if (positions[0][i][j] < positions[1][i][j]) {
                // position claimed by second team
                if (reference_team_id == 0) {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                }
            } else {
                // no change
            }

            if (this->show_self && positions[2][i][j] > 0.f) {
                // position claimed by second team
                result[i][j][0] = result[i][j][1] = 0x00;
                result[i][j][2] = result[i][j][3] = 0xFF;
            }

            if (deaths[0][i][j] + deaths[1][i][j] > 0.f) {
                static int offsets[][2] = {
                    {-1, -1},
                    {-1,  0},
                    {-1,  1},
                    { 0,  1},
                    { 1,  1},
                    { 1,  0},
                    { 1, -1},
                    { 0, -1},
                    { 0,  0}
                };

                for (const auto &offset : offsets) {
                    int x = j + offset[0];
                    int y = i + offset[1];

                    // draw only if within bounds
                    if (x >= 0 && x < image_width && y >= 0  && y < image_height) {
                        result[y][x][3] = result[y][x][0] = result[y][x][1] = 0xFF;
                        result[y][x][2] = 0x00;
                    }
                }
            }
        }
    }
}

void image_writer_t::reset() {
    // initialize with empty image arrays
    initialized = false;
}

bool image_writer_t::is_initialized() const {
    return initialized;
}

void image_writer_t::set_show_self(bool show_self) {
    this->show_self = show_self;
}

bool image_writer_t::get_show_self() const {
    return show_self;
}

void image_writer_t::set_use_fixed_teamcolors(bool use_fixed_teamcolors) {
    this->use_fixed_teamcolors = use_fixed_teamcolors;
}

bool image_writer_t::get_use_fixed_teamcolors() const {
    return use_fixed_teamcolors;
}

void image_writer_t::set_recorder_team(int recorder_team) {
    this->recorder_team = recorder_team;
}

int image_writer_t::get_recorder_team() const {
    return recorder_team;
}

void image_writer_t::set_filter(filter_t filter) {
    this->filter = filter;
}

const arena_t &image_writer_t::get_arena() const {
    return arena;
}

const std::string &image_writer_t::get_game_mode() const {
    return game_mode;
}

void image_writer_t::merge(const image_writer_t &writer) {
    // TODO: implement this
    std::transform(positions.origin(), positions.origin() + positions.num_elements(),
                   writer.positions.origin(), positions.origin(), std::plus<float>());
}

int image_writer_t::get_image_height() const {
    return image_height;
}

void image_writer_t::set_image_height(int image_height) {
    this->image_height = image_height;
}

int image_writer_t::get_image_width() const {
    return image_width;
}

void image_writer_t::set_image_width(int image_width) {
    this->image_width = image_width;
}

bool image_writer_t::get_no_basemap() const {
    return no_basemap;
}

void image_writer_t::set_no_basemap(bool no_basemap) {
    this->no_basemap = no_basemap;
}

void image_writer_t::draw_basemap() {
    if (!no_basemap) {
        load_base_map(arena.mini_map);
        const size_t *shape = base.shape();
        result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
        draw_elements();
    } else {
        base.resize(boost::extents[image_width][image_height][4]);
    }
}
<commit_msg>Simplify drawing of deaths<commit_after>#include "arena.h"
#include "image_util.h"
#include "image_writer.h"
#include "logger.h"

#include <fstream>

using namespace wotreplay;

const int element_size = 48;

image_writer_t::image_writer_t()
    : filter([](const packet_t &){ return true; }),
      image_width(512), image_height(512)
{}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, int x, int y, int mask) {
    const size_t *shape = element.shape();
    const size_t *image_size = base.shape();
    for (int i = 0; i < shape[0]; ++i) {
        for (int j = 0; j < shape[1]; ++j) {
            // don't touch alpha channel, use from original
            for (int k = 0; k < 3; ++k) {
                if (((i + y) >= image_size[0]) || ((j + x) >= image_size[1])) {
                    continue;
                }
                base[i + y][j + x][k] = mix(base[i + y][j + x][k], base[i + y][j + x][k], (255 - element[i][j][3]) / 255.f,
                                    element[i][j][k] & ((mask >> ((4- (k + 1))*8)) & 0xFF), element[i][j][3] / 255.f);
            }
        }
    }
}

boost::multi_array<uint8_t, 3> image_writer_t::get_element(const std::string &name) {
    boost::multi_array<uint8_t, 3> element, resized_element;
    std::ifstream is("elements/" + name + ".png", std::ios::binary);
    read_png(is, element);
    double f = image_width / 512.0; // we need to scale the elements to the right size
    resize(element, element_size*f, element_size*f, resized_element);
    return resized_element;
}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, std::tuple<float, float> position, int mask) {
    auto shape = base.shape();
    auto element_shape = element.shape();
    float x,y;
    auto position3d = std::make_tuple(std::get<0>(position), 0.f, std::get<1>(position));
    std::tie(x,y) = get_2d_coord(position3d, arena.bounding_box, (int) shape[1], (int) shape[0]);
    draw_element(element, x - element_shape[1]/2, y - element_shape[0]/2, mask);
}

void image_writer_t::draw_grid(boost::multi_array<uint8_t, 3> &image) {
    const int grid_line_width = 2;
    const int grid_cells = 10;
    auto shape = image.shape();
    int grid_width = ((int) shape[1] - (grid_cells + 1) * grid_line_width) / grid_cells;
    int grid_height = ((int) shape[0] - (grid_cells + 1) * grid_line_width) / grid_cells;
    for (int y = 0; y < shape[0]; y += (grid_height + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int x = 0; x < shape[1]; ++x) {
                for (int c = 0; c < 3; ++ c) {
                    image[y + i][x][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
    for (int x = 0; x < shape[1]; x += (grid_width + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int y = 0; y < shape[0]; ++y) {
                for (int c = 0; c < 3; ++ c) {
                    image[y][x + i][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
}

void image_writer_t::draw_elements() {
    auto it = arena.configurations.find(game_mode);
    if (it == arena.configurations.end()) {
        wotreplay::logger.writef(log_level_t::warning, "Could not find configuration for game mode '%1%'\n", game_mode);
        return;
    }

    const arena_configuration_t &configuration = arena.configurations[game_mode];
    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;

    if (game_mode == "domination") {
        auto neutral_base = get_element("neutral_base");
        draw_element(neutral_base, configuration.control_point);
    }

    auto friendly_base = get_element("friendly_base");
    auto enemy_base = get_element("enemy_base");
    for(const auto &entry : configuration.team_base_positions) {
        for (const auto &position : entry.second) {
            draw_element((entry.first - 1) == reference_team_id ? friendly_base : enemy_base, position);
        }
    }

    std::vector<boost::multi_array<uint8_t, 3>> spawns{
        get_element("neutral_spawn1"),
        get_element("neutral_spawn2"),
        get_element("neutral_spawn3"),
        get_element("neutral_spawn4")
    };

    for(const auto &entry : configuration.team_spawn_points) {
        for (int i = 0; i < entry.second.size(); ++i) {
            int mask = (reference_team_id == (entry.first - 1)) ? 0x00FF00FF : 0xFF0000FF;
            draw_element(spawns[i], entry.second[i], mask);
        }
    }

    draw_grid(base);
}

void image_writer_t::draw_death(const packet_t &packet, const game_t &game) {
    uint32_t killer, killed;
    std::tie(killed, killer) = packet.tank_destroyed();
    packet_t position_packet;
    bool found = game.find_property(packet.clock(), killed, property_t::position, position_packet);
    if (found) {
        draw_position(position_packet, game, this->deaths);
    }
}

void image_writer_t::draw_position(const packet_t &packet, const game_t &game, boost::multi_array<float, 3> &image) {
    uint32_t player_id = packet.player_id();

    int team_id = game.get_team_id(player_id);
    if (team_id < 0) return;

    auto shape = image.shape();
    int height = static_cast<int>(shape[1]);
    int width = static_cast<int>(shape[2]);

    const bounding_box_t &bounding_box = game.get_arena().bounding_box;
    std::tuple<float, float> position = get_2d_coord( packet.position(), bounding_box, width, height);
    long x = std::lround(std::get<0>(position));
    long y = std::lround(std::get<1>(position));
    if (x >= 0 && y >= 0 && x < width && y < height) {
        image[team_id][y][x]++;
        if (player_id == game.get_recorder_id()) {
            image[2][y][x]++;
        }
    }
}

void image_writer_t::update(const game_t &game) {
    recorder_team = game.get_team_id(game.get_recorder_id());

    std::set<int> dead_players;
    for (const packet_t &packet : game.get_packets()) {
        if (!filter(packet)) continue;
        if (packet.has_property(property_t::position)
            && dead_players.find(packet.player_id()) == dead_players.end()) {
            draw_position(packet, game, this->positions);
        } else if (packet.has_property(property_t::tank_destroyed)) {
            uint32_t target, killer;
            std::tie(target, killer) = packet.tank_destroyed();
            dead_players.insert(target);
            draw_death(packet, game);
        }
    }
}

void image_writer_t::load_base_map(const std::string &path) {
    boost::multi_array<uint8_t, 3> map;
    std::ifstream is(path, std::ios::binary);
    read_png(is, map);
    resize(map, image_width, image_height, this->base);
}

void image_writer_t::write(std::ostream &os) {
    write_png(os, result);
}

void image_writer_t::init(const arena_t &arena, const std::string &mode) {
    this->arena = arena;
    this->game_mode = mode;

    positions.resize(boost::extents[3][image_height][image_width]);
    deaths.resize(boost::extents[3][image_height][image_width]);

    clear();

    initialized = true;
}

void image_writer_t::clear() {
    std::fill(result.origin(), result.origin() + result.num_elements(), 0.f);
    std::fill(deaths.origin(), deaths.origin() + deaths.num_elements(), 0.f);
    std::fill(positions.origin(), positions.origin() + positions.num_elements(), 0.f);
}

void image_writer_t::finish() {
    draw_basemap();

    const size_t *shape = base.shape();
    result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
    result = base;

    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;
    for (int i = 0; i < image_height; ++i) {
        for (int j = 0; j < image_width; ++j) {
            if (positions[0][i][j] > positions[1][i][j]) {
                // position claimed by first team
                if (reference_team_id == 0) {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                }

            } else if (positions[0][i][j] < positions[1][i][j]) {
                // position claimed by second team
                if (reference_team_id == 0) {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                }
            } else {
                // no change
            }

            if (this->show_self && positions[2][i][j] > 0.f) {
                // position claimed by second team
                result[i][j][0] = result[i][j][1] = 0x00;
                result[i][j][2] = result[i][j][3] = 0xFF;
            }

            if (deaths[0][i][j] + deaths[1][i][j] > 0.f) {
				for (int k = 0; k < 3; k += 1) {
					for (int l = 0; l < 3; l += 1) {
						int x = j + k - 1;
						int y = i + l - 1;

						// draw only if within bounds
						if (x >= 0 && x < image_width && y >= 0 && y < image_height) {
							result[y][x][3] = result[y][x][0] = result[y][x][1] = 0xFF;
							result[y][x][2] = 0x00;
						}
					}
				}
            }
        }
    }
}

void image_writer_t::reset() {
    // initialize with empty image arrays
    initialized = false;
}

bool image_writer_t::is_initialized() const {
    return initialized;
}

void image_writer_t::set_show_self(bool show_self) {
    this->show_self = show_self;
}

bool image_writer_t::get_show_self() const {
    return show_self;
}

void image_writer_t::set_use_fixed_teamcolors(bool use_fixed_teamcolors) {
    this->use_fixed_teamcolors = use_fixed_teamcolors;
}

bool image_writer_t::get_use_fixed_teamcolors() const {
    return use_fixed_teamcolors;
}

void image_writer_t::set_recorder_team(int recorder_team) {
    this->recorder_team = recorder_team;
}

int image_writer_t::get_recorder_team() const {
    return recorder_team;
}

void image_writer_t::set_filter(filter_t filter) {
    this->filter = filter;
}

const arena_t &image_writer_t::get_arena() const {
    return arena;
}

const std::string &image_writer_t::get_game_mode() const {
    return game_mode;
}

void image_writer_t::merge(const image_writer_t &writer) {
    // TODO: implement this
    std::transform(positions.origin(), positions.origin() + positions.num_elements(),
                   writer.positions.origin(), positions.origin(), std::plus<float>());
}

int image_writer_t::get_image_height() const {
    return image_height;
}

void image_writer_t::set_image_height(int image_height) {
    this->image_height = image_height;
}

int image_writer_t::get_image_width() const {
    return image_width;
}

void image_writer_t::set_image_width(int image_width) {
    this->image_width = image_width;
}

bool image_writer_t::get_no_basemap() const {
    return no_basemap;
}

void image_writer_t::set_no_basemap(bool no_basemap) {
    this->no_basemap = no_basemap;
}

void image_writer_t::draw_basemap() {
    if (!no_basemap) {
        load_base_map(arena.mini_map);
        const size_t *shape = base.shape();
        result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
        draw_elements();
    } else {
        base.resize(boost::extents[image_width][image_height][4]);
    }
}
<|endoftext|>


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

#include "Precompiled.h"
#include "Button.h"
#include "Context.h"
#include "Graphics.h"
#include "Log.h"
#include "MessageBox.h"
#include "ResourceCache.h"
#include "Text.h"
#include "UI.h"
#include "UIEvents.h"
#include "Window.h"
#include "XMLFile.h"

namespace Urho3D
{

MessageBox::MessageBox(Context* context, const String& messageString, const String& titleString, XMLFile* layoutFile, XMLFile* styleFile) :
    Object(context),
    titleText_(0),
    messageText_(0),
    okButton_(0)
{
    // If layout file is not given, use the default message box layout
    if (!layoutFile)
    {
        ResourceCache* cache = GetSubsystem<ResourceCache>();
        layoutFile = cache->GetResource<XMLFile>("UI/MessageBox.xml");
        if (!layoutFile)    // Error is already logged
            return;         // Note: windowless MessageBox should not be used!
    }

    UI* ui = GetSubsystem<UI>();
    window_ = ui->LoadLayout(layoutFile, styleFile);
    ui->GetRoot()->AddChild(window_);

    // Set the title and message strings if they are given
    titleText_ = dynamic_cast<Text*>(window_->GetChild("TitleText", true));
    if (titleText_ && !titleString.Empty())
        titleText_->SetText(titleString);
    messageText_ = dynamic_cast<Text*>(window_->GetChild("MessageText", true));
    if (messageText_ && !messageString.Empty())
        messageText_->SetText(messageString);

    // Center window after the message is set
    Window* window = dynamic_cast<Window*>(window_.Get());
    if (window)
    {
        Graphics* graphics = GetSubsystem<Graphics>();  // May be null if headless
        if (graphics)
        {
            const IntVector2& size = window->GetSize();
            window->SetPosition((graphics->GetWidth() - size.x_) / 2, (graphics->GetHeight() - size.y_) / 2);
        }
        else
            LOGWARNING("Instantiating a modal window in headless mode!");

        window->SetModal(true);
        SubscribeToEvent(window, E_MODALCHANGED, HANDLER(MessageBox, HandleMessageAcknowledged));
    }

    // Bind the buttons (if any in the loaded UI layout) to event handlers
    okButton_ = dynamic_cast<Button*>(window_->GetChild("OkButton", true));
    if (okButton_)
    {
        ui->SetFocusElement(okButton_);
        SubscribeToEvent(okButton_, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
    }
    Button* cancelButton = dynamic_cast<Button*>(window_->GetChild("CancelButton", true));
    if (cancelButton)
        SubscribeToEvent(cancelButton, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
    Button* closeButton = dynamic_cast<Button*>(window_->GetChild("CloseButton", true));
    if (closeButton)
        SubscribeToEvent(closeButton, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
}

MessageBox::~MessageBox()
{
    if (window_)
        window_->Remove();
}

void MessageBox::RegisterObject(Context* context)
{
    context->RegisterFactory<MessageBox>();
}

void MessageBox::SetTitle(const String& text)
{
    if (titleText_)
        titleText_->SetText(text);
}

void MessageBox::SetMessage(const String& text)
{
    if (messageText_)
        messageText_->SetText(text);
}

const String& MessageBox::GetTitle() const
{
    return titleText_ ? titleText_->GetText() : String::EMPTY;
}

const String& MessageBox::GetMessage() const
{
    return messageText_ ? messageText_->GetText() : String::EMPTY;
}

void MessageBox::HandleMessageAcknowledged(StringHash eventType, VariantMap& eventData)
{
    using namespace MessageACK;

    VariantMap& newEventData = GetEventDataMap();
    newEventData[P_OK] = eventData[Released::P_ELEMENT] == okButton_;
    SendEvent(E_MESSAGEACK, newEventData);

    this->ReleaseRef();
}

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

#include "Precompiled.h"
#include "Button.h"
#include "Context.h"
#include "Graphics.h"
#include "Log.h"
#include "MessageBox.h"
#include "ResourceCache.h"
#include "Text.h"
#include "UI.h"
#include "UIEvents.h"
#include "Window.h"
#include "XMLFile.h"

namespace Urho3D
{

MessageBox::MessageBox(Context* context, const String& messageString, const String& titleString, XMLFile* layoutFile, XMLFile* styleFile) :
    Object(context),
    titleText_(0),
    messageText_(0),
    okButton_(0)
{
    // If layout file is not given, use the default message box layout
    if (!layoutFile)
    {
        ResourceCache* cache = GetSubsystem<ResourceCache>();
        layoutFile = cache->GetResource<XMLFile>("UI/MessageBox.xml");
        if (!layoutFile)    // Error is already logged
            return;         // Note: windowless MessageBox should not be used!
    }

    UI* ui = GetSubsystem<UI>();
    window_ = ui->LoadLayout(layoutFile, styleFile);
    if (!window_)   // Error is already logged
        return;
    ui->GetRoot()->AddChild(window_);

    // Set the title and message strings if they are given
    titleText_ = dynamic_cast<Text*>(window_->GetChild("TitleText", true));
    if (titleText_ && !titleString.Empty())
        titleText_->SetText(titleString);
    messageText_ = dynamic_cast<Text*>(window_->GetChild("MessageText", true));
    if (messageText_ && !messageString.Empty())
        messageText_->SetText(messageString);

    // Center window after the message is set
    Window* window = dynamic_cast<Window*>(window_.Get());
    if (window)
    {
        Graphics* graphics = GetSubsystem<Graphics>();  // May be null if headless
        if (graphics)
        {
            const IntVector2& size = window->GetSize();
            window->SetPosition((graphics->GetWidth() - size.x_) / 2, (graphics->GetHeight() - size.y_) / 2);
        }
        else
            LOGWARNING("Instantiating a modal window in headless mode!");

        window->SetModal(true);
        SubscribeToEvent(window, E_MODALCHANGED, HANDLER(MessageBox, HandleMessageAcknowledged));
    }

    // Bind the buttons (if any in the loaded UI layout) to event handlers
    okButton_ = dynamic_cast<Button*>(window_->GetChild("OkButton", true));
    if (okButton_)
    {
        ui->SetFocusElement(okButton_);
        SubscribeToEvent(okButton_, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
    }
    Button* cancelButton = dynamic_cast<Button*>(window_->GetChild("CancelButton", true));
    if (cancelButton)
        SubscribeToEvent(cancelButton, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
    Button* closeButton = dynamic_cast<Button*>(window_->GetChild("CloseButton", true));
    if (closeButton)
        SubscribeToEvent(closeButton, E_RELEASED, HANDLER(MessageBox, HandleMessageAcknowledged));
}

MessageBox::~MessageBox()
{
    if (window_)
        window_->Remove();
}

void MessageBox::RegisterObject(Context* context)
{
    context->RegisterFactory<MessageBox>();
}

void MessageBox::SetTitle(const String& text)
{
    if (titleText_)
        titleText_->SetText(text);
}

void MessageBox::SetMessage(const String& text)
{
    if (messageText_)
        messageText_->SetText(text);
}

const String& MessageBox::GetTitle() const
{
    return titleText_ ? titleText_->GetText() : String::EMPTY;
}

const String& MessageBox::GetMessage() const
{
    return messageText_ ? messageText_->GetText() : String::EMPTY;
}

void MessageBox::HandleMessageAcknowledged(StringHash eventType, VariantMap& eventData)
{
    using namespace MessageACK;

    VariantMap& newEventData = GetEventDataMap();
    newEventData[P_OK] = eventData[Released::P_ELEMENT] == okButton_;
    SendEvent(E_MESSAGEACK, newEventData);

    this->ReleaseRef();
}

}
<|endoftext|>