<commit_before>#include <algorithm>
#include "../Headers/neural_network.h"

using namespace Hippocrates;
using namespace std;

NeuralNetwork::NeuralNetwork(const Genome& genome, bool shouldMutate) :
	genome(genome),
	inputNeurons(genome.GetInputCount()),
	outputNeurons(genome.GetOutputCount())
{
	if (shouldMutate) {
		MutateGenesAndBuildNetwork();
	}
	else {
		BuildNetworkFromGenes();
	}
}

NeuralNetwork::NeuralNetwork(Genome&& genome, bool shouldMutate) :
	genome(move(genome)),
	inputNeurons(genome.GetInputCount()),
	outputNeurons(genome.GetOutputCount())
{
	if (shouldMutate) {
		MutateGenesAndBuildNetwork();
	}
	else {
		BuildNetworkFromGenes();
	}
}

NeuralNetwork::NeuralNetwork(const NeuralNetwork& other) :
	genome(other.genome),
	inputNeurons(other.inputNeurons.size()),
	outputNeurons(other.outputNeurons.size())
{
	BuildNetworkFromGenes();
}

auto NeuralNetwork::operator=(const NeuralNetwork& other) -> NeuralNetwork& {
	genome = other.genome;
	inputNeurons.resize(other.inputNeurons.size());
	outputNeurons.resize(other.outputNeurons.size());
	neurons.clear();
	neurons.reserve(other.neurons.size());
	layerMap.clear();
	BuildNetworkFromGenes();
	return *this;
}

auto NeuralNetwork::BuildNetworkFromGenes() -> void {
	neurons.resize(genome.GetNeuronCount());
	for (const auto& gene : genome) {
		if (gene.isEnabled) {
			Neuron::Connection in;
			in.weight = gene.weight;
			in.isRecursive = gene.isRecursive;
			in.neuron = &neurons[gene.from];
			neurons[gene.to].AddConnection(move(in));

			Neuron::Connection out;
			out.weight = gene.weight;
			out.isRecursive = gene.isRecursive;
			out.neuron = &neurons[gene.to];
			out.outGoing = true;
			neurons[gene.from].AddConnection(move(out));
		}
	}
	InterpretInputsAndOutputs();
	CategorizeNeuronsIntoLayers();
}

auto NeuralNetwork::SetInputs(vector<float> inputs) -> void {
	if (inputNeurons.size() != inputs.size()) {
		throw out_of_range("Number of inputs provided doesn't match genetic information");
	}
	for (size_t i = 0U; i < inputNeurons.size(); ++i) {
		inputNeurons[i]->SetInput(move(inputs[i]));
	};
}

auto NeuralNetwork::GetOutputs() -> vector<float> {
	for (size_t i = 1; i < layerMap.size() - 1; ++i) {
		for (auto& neuron : layerMap[i]) {
			neuron->RequestDataAndGetActionPotential();
		}
	}
	vector<float> outputs;
	outputs.reserve(outputNeurons.size());
	for (auto& outputNeuron : outputNeurons) {
		outputs.push_back(outputNeuron->RequestDataAndGetActionPotential());
	}
	return outputs;
}

auto NeuralNetwork::GetOutputsUsingInputs(vector<float> inputs) -> vector<float> {
	SetInputs(move(inputs));
	return GetOutputs();
}

auto NeuralNetwork::InterpretInputsAndOutputs() -> void {
	// Bias
	for (auto i = 0U; i < GetTrainingParameters().structure.numberOfBiasNeurons; i++) {
		neurons[i].SetInput(1.0f);
	}

	// Inputs
	for (auto i = 0U; i < genome.GetInputCount(); i++) {
		inputNeurons[i] = &neurons[i + GetTrainingParameters().structure.numberOfBiasNeurons];
	}

	// Outputs
	for (auto i = 0U; i < genome.GetOutputCount(); i++) {
		outputNeurons[i] = &neurons[genome[i].to];
	}
}

auto NeuralNetwork::ShouldAddNeuron() const -> bool {
	return DidChanceOccure(
		GetTrainingParameters().

		mutation.
		chanceForNeuralMutation
	);
}

auto NeuralNetwork::ShouldAddConnection() const -> bool {
	const bool hasChanceOccured = DidChanceOccure(GetTrainingParameters().mutation.chanceForConnectionalMutation);
	if (!hasChanceOccured) {
		return false;
	}
	const size_t inputLayerSize = genome.GetInputCount() + GetTrainingParameters().structure.numberOfBiasNeurons;
	const size_t outputLayerSize = genome.GetOutputCount();
	const size_t hiddenLayerSize = genome.GetNeuronCount() - inputLayerSize - outputLayerSize;

	const auto startingConnections = inputLayerSize * outputLayerSize;
	auto hiddenConnections = (hiddenLayerSize * (hiddenLayerSize - 1));
	if (!GetTrainingParameters().structure.allowRecursiveConnections) {
		hiddenConnections /= 2;
	}
	const auto connectionsFromInputs = inputLayerSize * hiddenLayerSize;
	auto connectionsToOutputs = outputLayerSize * hiddenLayerSize;
	if (GetTrainingParameters().structure.allowRecursiveConnections) {
		connectionsToOutputs *= 2;
	}

	const auto possibleConnections =
		startingConnections +
	    hiddenConnections +
		connectionsFromInputs +
		connectionsToOutputs;
	return genome.GetGeneCount() < possibleConnections;
}

auto NeuralNetwork::ShouldMutateWeight() const -> bool {
	return DidChanceOccure(
		GetTrainingParameters().
		mutation.
		chanceForWeightMutation
	);
}

auto NeuralNetwork::DidChanceOccure(float chance) -> bool {
	auto num = rand() % 100;
	return num < int(100.0f * chance);
}

auto NeuralNetwork::AddRandomNeuron() -> void {
	auto& randGene = GetRandomEnabledGene();
	auto indexOfNewNeuron = genome.GetNeuronCount();

	Gene g1;
	g1.from = randGene.from;
	g1.to = indexOfNewNeuron;
	g1.weight = 1.0f;
	g1.isRecursive = randGene.isRecursive;

	Gene g2;
	g2.from = indexOfNewNeuron;
	g2.to = randGene.to;
	g2.weight = randGene.weight;
	g2.isRecursive = randGene.isRecursive;

	randGene.isEnabled = false;

	genome.AppendGene(move(g1));
	genome.AppendGene(move(g2));
}

auto NeuralNetwork::AddRandomConnection() -> void {
	// Data
	auto NeuronPair(GetTwoUnconnectedNeurons());
	auto& fromNeuron = *NeuronPair.first;
	auto& toNeuron = *NeuronPair.second;

	// Gene
	Gene newConnectionGene;
	while (&neurons[newConnectionGene.from] != &fromNeuron) {
		newConnectionGene.from++;
	}
	while (&neurons[newConnectionGene.to] != &toNeuron) {
		newConnectionGene.to++;
	}
	if (fromNeuron.GetLayer() > toNeuron.GetLayer()) {
		newConnectionGene.isRecursive = true;
	}

	// Connection
	Neuron::Connection in;
	in.isRecursive = newConnectionGene.isRecursive;
	in.neuron = &fromNeuron;
	in.weight = newConnectionGene.weight;
	toNeuron.AddConnection(move(in));

	Neuron::Connection out;
	out.isRecursive = newConnectionGene.isRecursive;
	out.neuron = &toNeuron;
	out.weight = newConnectionGene.weight;
	out.outGoing = true;
	fromNeuron.AddConnection(move(out));

	genome.AppendGene(move(newConnectionGene));
	CategorizeNeuronsIntoLayers();
}

auto NeuralNetwork::GetTwoUnconnectedNeurons() -> pair<Neuron*, Neuron*> {
	vector<Neuron*> possibleFromNeurons;
	possibleFromNeurons.reserve(neurons.size());
	for (auto& n : neurons) {
		possibleFromNeurons.push_back(&n);
	}
	auto inputRange = genome.GetInputCount() + GetTrainingParameters().structure.numberOfBiasNeurons;
	vector<Neuron*> possibleToNeurons(possibleFromNeurons.begin() + inputRange, possibleFromNeurons.end());

	random_shuffle(possibleFromNeurons.begin(), possibleFromNeurons.end());
	random_shuffle(possibleToNeurons.begin(), possibleToNeurons.end());

	for (auto* from : possibleFromNeurons) {
		for (auto* to : possibleToNeurons) {
			if (CanNeuronsBeConnected(*from, *to)) {
				return{ from, to };
			}
		}
	}

	throw runtime_error("Tried to get two unconnected Neurons while every neuron is already connected");
}

auto Hippocrates::NeuralNetwork::CanNeuronsBeConnected(const Neuron & lhs, const Neuron & rhs) const -> bool {
	bool AreNeuronsTheSame = &lhs == &rhs;
	return (!AreNeuronsTheSame && !AreBothNeuronsOutputs(lhs, rhs) && !AreNeuronsConnected(lhs, rhs));
}

auto NeuralNetwork::AreBothNeuronsOutputs(const Neuron &lhs, const Neuron &rhs) const -> bool {
	bool isLhsOutput = false;
	bool isRhsOutput = false;
	for (const auto& output : outputNeurons) {
		if (output == &lhs) {
			isLhsOutput = true;
		}
		else if (output == &rhs) {
			isRhsOutput = true;
		}
		if (isLhsOutput && isRhsOutput) {
			return true;
		}
	}
	return false;
}

auto NeuralNetwork::AreNeuronsConnected(const Neuron& lhs, const Neuron & rhs) -> bool {
	for (auto& connection : rhs.GetConnections()) {
		if (!connection.outGoing && &lhs == connection.neuron) {
			return true;
		}
	}
	return false;
}

auto NeuralNetwork::ShuffleWeights() -> void {
	for (size_t i = 0; i < genome.GetGeneCount(); i++) {
		if (ShouldMutateWeight()) {
			MutateWeightOfGeneAt(i);
		}
	}
}

auto NeuralNetwork::MutateWeightOfGeneAt(size_t index) -> void {
	if (DidChanceOccure(GetTrainingParameters().mutation.chanceOfTotalWeightReset)) {
		genome[index].SetRandomWeight();
	}
	else {
		PerturbWeightAt(index);
	}
}

auto NeuralNetwork::PerturbWeightAt(size_t index) -> void {
	constexpr float perturbanceBoundaries = 0.5f;
	auto perturbance = static_cast<float>(rand() % 10'000) / 9'999.0f * perturbanceBoundaries;
	if (rand() % 2) {
		perturbance = -perturbance;
	}
	genome[index].weight += perturbance;
	if (genome[index].weight < -1.0f) {
		genome[index].weight = -1.0f;
	}
	else if (genome[index].weight > 1.0f) {
		genome[index].weight = 1.0f;
	}
}

auto NeuralNetwork::MutateGenesAndBuildNetwork() -> void {
	if (ShouldAddConnection()) {
		BuildNetworkFromGenes();
		AddRandomConnection();
	}
	else {
		if (ShouldAddNeuron()) {
			AddRandomNeuron();
		} else {
			ShuffleWeights();
		}

		BuildNetworkFromGenes();
	}
}

auto NeuralNetwork::CategorizeNeuronsIntoLayers() -> void {
	for (auto i = 0U; i < GetTrainingParameters().structure.numberOfBiasNeurons; i++) {
		CategorizeNeuronBranchIntoLayers(neurons[i]);
	}
	for (auto* in : inputNeurons) {
		CategorizeNeuronBranchIntoLayers(*in);
	}

	size_t highestLayer = 0U;
	for (auto* out : outputNeurons) {
		highestLayer = max(out->GetLayer(), highestLayer);
	}
	for (auto* out : outputNeurons) {
		out->layer = highestLayer;
	}

	for (auto& neuron : neurons) {
		layerMap[neuron.GetLayer()].push_back(&neuron);
	}
}

auto NeuralNetwork::CategorizeNeuronBranchIntoLayers(Neuron& currNode, size_t currentDepth) const -> void {
	currNode.layer = currentDepth;
	const auto nextLayer = currNode.layer + 1;

	auto HasYetToBeLayered = [&nextLayer](const auto& connection) {
		return nextLayer > connection.neuron->layer;
	};
	auto IsInHigherLayer = [](const auto& connection) {
		return (connection.outGoing != connection.isRecursive);
	};

	for (auto &connection : currNode.GetConnections()) {
		if (HasYetToBeLayered(connection) && IsInHigherLayer(connection)) {
			CategorizeNeuronBranchIntoLayers(*connection.neuron, nextLayer);
		}
	}
}

auto NeuralNetwork::GetRandomEnabledGene() -> Gene& {
	size_t num = rand() % genome.GetGeneCount();
	auto randGene = genome.begin();
	randGene += num;
	while (randGene != genome.end() && !randGene->isEnabled) {
		++randGene;
	}
	if (randGene == genome.end()) {
		randGene = genome.begin() + num;
		while (randGene != genome.begin() && !randGene->isEnabled) {
			--randGene;
		}
	}
	if (!randGene->isEnabled) {
		throw runtime_error("Could not insert neuron because every gene is disabled");
	}
	return *randGene;
}

auto NeuralNetwork::GetJSON() const -> string {
	string s("{\"neurons\":[");
	for (size_t i = 0; i < neurons.size() - 1; ++i) {
		s += neurons[i].GetJSON();
		s += ",";
	}
	s += neurons.back().GetJSON();
	s += "],\"genome\":";
	s += genome.GetJSON();
	s += "}";
	return s;
}
<commit_msg>Remove unneeded brackets<commit_after>#include <algorithm>
#include "../Headers/neural_network.h"

using namespace Hippocrates;
using namespace std;

NeuralNetwork::NeuralNetwork(const Genome& genome, bool shouldMutate) :
	genome(genome),
	inputNeurons(genome.GetInputCount()),
	outputNeurons(genome.GetOutputCount())
{
	if (shouldMutate) {
		MutateGenesAndBuildNetwork();
	}
	else {
		BuildNetworkFromGenes();
	}
}

NeuralNetwork::NeuralNetwork(Genome&& genome, bool shouldMutate) :
	genome(move(genome)),
	inputNeurons(genome.GetInputCount()),
	outputNeurons(genome.GetOutputCount())
{
	if (shouldMutate) {
		MutateGenesAndBuildNetwork();
	}
	else {
		BuildNetworkFromGenes();
	}
}

NeuralNetwork::NeuralNetwork(const NeuralNetwork& other) :
	genome(other.genome),
	inputNeurons(other.inputNeurons.size()),
	outputNeurons(other.outputNeurons.size())
{
	BuildNetworkFromGenes();
}

auto NeuralNetwork::operator=(const NeuralNetwork& other) -> NeuralNetwork& {
	genome = other.genome;
	inputNeurons.resize(other.inputNeurons.size());
	outputNeurons.resize(other.outputNeurons.size());
	neurons.clear();
	neurons.reserve(other.neurons.size());
	layerMap.clear();
	BuildNetworkFromGenes();
	return *this;
}

auto NeuralNetwork::BuildNetworkFromGenes() -> void {
	neurons.resize(genome.GetNeuronCount());
	for (const auto& gene : genome) {
		if (gene.isEnabled) {
			Neuron::Connection in;
			in.weight = gene.weight;
			in.isRecursive = gene.isRecursive;
			in.neuron = &neurons[gene.from];
			neurons[gene.to].AddConnection(move(in));

			Neuron::Connection out;
			out.weight = gene.weight;
			out.isRecursive = gene.isRecursive;
			out.neuron = &neurons[gene.to];
			out.outGoing = true;
			neurons[gene.from].AddConnection(move(out));
		}
	}
	InterpretInputsAndOutputs();
	CategorizeNeuronsIntoLayers();
}

auto NeuralNetwork::SetInputs(vector<float> inputs) -> void {
	if (inputNeurons.size() != inputs.size()) {
		throw out_of_range("Number of inputs provided doesn't match genetic information");
	}
	for (size_t i = 0U; i < inputNeurons.size(); ++i) {
		inputNeurons[i]->SetInput(move(inputs[i]));
	};
}

auto NeuralNetwork::GetOutputs() -> vector<float> {
	for (size_t i = 1; i < layerMap.size() - 1; ++i) {
		for (auto& neuron : layerMap[i]) {
			neuron->RequestDataAndGetActionPotential();
		}
	}
	vector<float> outputs;
	outputs.reserve(outputNeurons.size());
	for (auto& outputNeuron : outputNeurons) {
		outputs.push_back(outputNeuron->RequestDataAndGetActionPotential());
	}
	return outputs;
}

auto NeuralNetwork::GetOutputsUsingInputs(vector<float> inputs) -> vector<float> {
	SetInputs(move(inputs));
	return GetOutputs();
}

auto NeuralNetwork::InterpretInputsAndOutputs() -> void {
	// Bias
	for (auto i = 0U; i < GetTrainingParameters().structure.numberOfBiasNeurons; i++) {
		neurons[i].SetInput(1.0f);
	}

	// Inputs
	for (auto i = 0U; i < genome.GetInputCount(); i++) {
		inputNeurons[i] = &neurons[i + GetTrainingParameters().structure.numberOfBiasNeurons];
	}

	// Outputs
	for (auto i = 0U; i < genome.GetOutputCount(); i++) {
		outputNeurons[i] = &neurons[genome[i].to];
	}
}

auto NeuralNetwork::ShouldAddNeuron() const -> bool {
	return DidChanceOccure(
		GetTrainingParameters().

		mutation.
		chanceForNeuralMutation
	);
}

auto NeuralNetwork::ShouldAddConnection() const -> bool {
	const bool hasChanceOccured = DidChanceOccure(GetTrainingParameters().mutation.chanceForConnectionalMutation);
	if (!hasChanceOccured) {
		return false;
	}
	const auto inputLayerSize = genome.GetInputCount() + GetTrainingParameters().structure.numberOfBiasNeurons;
	const auto outputLayerSize = genome.GetOutputCount();
	const auto hiddenLayerSize = genome.GetNeuronCount() - inputLayerSize - outputLayerSize;

	const auto startingConnections = inputLayerSize * outputLayerSize;
	auto hiddenConnections = hiddenLayerSize * (hiddenLayerSize - 1);
	if (!GetTrainingParameters().structure.allowRecursiveConnections) {
		hiddenConnections /= 2;
	}
	const auto connectionsFromInputs = inputLayerSize * hiddenLayerSize;
	auto connectionsToOutputs = outputLayerSize * hiddenLayerSize;
	if (GetTrainingParameters().structure.allowRecursiveConnections) {
		connectionsToOutputs *= 2;
	}

	const auto possibleConnections =
		startingConnections +
	    hiddenConnections +
		connectionsFromInputs +
		connectionsToOutputs;
	return genome.GetGeneCount() < possibleConnections;
}

auto NeuralNetwork::ShouldMutateWeight() const -> bool {
	return DidChanceOccure(
		GetTrainingParameters().
		mutation.
		chanceForWeightMutation
	);
}

auto NeuralNetwork::DidChanceOccure(float chance) -> bool {
	auto num = rand() % 100;
	return num < int(100.0f * chance);
}

auto NeuralNetwork::AddRandomNeuron() -> void {
	auto& randGene = GetRandomEnabledGene();
	auto indexOfNewNeuron = genome.GetNeuronCount();

	Gene g1;
	g1.from = randGene.from;
	g1.to = indexOfNewNeuron;
	g1.weight = 1.0f;
	g1.isRecursive = randGene.isRecursive;

	Gene g2;
	g2.from = indexOfNewNeuron;
	g2.to = randGene.to;
	g2.weight = randGene.weight;
	g2.isRecursive = randGene.isRecursive;

	randGene.isEnabled = false;

	genome.AppendGene(move(g1));
	genome.AppendGene(move(g2));
}

auto NeuralNetwork::AddRandomConnection() -> void {
	// Data
	auto NeuronPair(GetTwoUnconnectedNeurons());
	auto& fromNeuron = *NeuronPair.first;
	auto& toNeuron = *NeuronPair.second;

	// Gene
	Gene newConnectionGene;
	while (&neurons[newConnectionGene.from] != &fromNeuron) {
		newConnectionGene.from++;
	}
	while (&neurons[newConnectionGene.to] != &toNeuron) {
		newConnectionGene.to++;
	}
	if (fromNeuron.GetLayer() > toNeuron.GetLayer()) {
		newConnectionGene.isRecursive = true;
	}

	// Connection
	Neuron::Connection in;
	in.isRecursive = newConnectionGene.isRecursive;
	in.neuron = &fromNeuron;
	in.weight = newConnectionGene.weight;
	toNeuron.AddConnection(move(in));

	Neuron::Connection out;
	out.isRecursive = newConnectionGene.isRecursive;
	out.neuron = &toNeuron;
	out.weight = newConnectionGene.weight;
	out.outGoing = true;
	fromNeuron.AddConnection(move(out));

	genome.AppendGene(move(newConnectionGene));
	CategorizeNeuronsIntoLayers();
}

auto NeuralNetwork::GetTwoUnconnectedNeurons() -> pair<Neuron*, Neuron*> {
	vector<Neuron*> possibleFromNeurons;
	possibleFromNeurons.reserve(neurons.size());
	for (auto& n : neurons) {
		possibleFromNeurons.push_back(&n);
	}
	auto inputRange = genome.GetInputCount() + GetTrainingParameters().structure.numberOfBiasNeurons;
	vector<Neuron*> possibleToNeurons(possibleFromNeurons.begin() + inputRange, possibleFromNeurons.end());

	random_shuffle(possibleFromNeurons.begin(), possibleFromNeurons.end());
	random_shuffle(possibleToNeurons.begin(), possibleToNeurons.end());

	for (auto* from : possibleFromNeurons) {
		for (auto* to : possibleToNeurons) {
			if (CanNeuronsBeConnected(*from, *to)) {
				return{ from, to };
			}
		}
	}

	throw runtime_error("Tried to get two unconnected Neurons while every neuron is already connected");
}

auto Hippocrates::NeuralNetwork::CanNeuronsBeConnected(const Neuron & lhs, const Neuron & rhs) const -> bool {
	bool AreNeuronsTheSame = &lhs == &rhs;
	return (!AreNeuronsTheSame && !AreBothNeuronsOutputs(lhs, rhs) && !AreNeuronsConnected(lhs, rhs));
}

auto NeuralNetwork::AreBothNeuronsOutputs(const Neuron &lhs, const Neuron &rhs) const -> bool {
	bool isLhsOutput = false;
	bool isRhsOutput = false;
	for (const auto& output : outputNeurons) {
		if (output == &lhs) {
			isLhsOutput = true;
		}
		else if (output == &rhs) {
			isRhsOutput = true;
		}
		if (isLhsOutput && isRhsOutput) {
			return true;
		}
	}
	return false;
}

auto NeuralNetwork::AreNeuronsConnected(const Neuron& lhs, const Neuron & rhs) -> bool {
	for (auto& connection : rhs.GetConnections()) {
		if (!connection.outGoing && &lhs == connection.neuron) {
			return true;
		}
	}
	return false;
}

auto NeuralNetwork::ShuffleWeights() -> void {
	for (size_t i = 0; i < genome.GetGeneCount(); i++) {
		if (ShouldMutateWeight()) {
			MutateWeightOfGeneAt(i);
		}
	}
}

auto NeuralNetwork::MutateWeightOfGeneAt(size_t index) -> void {
	if (DidChanceOccure(GetTrainingParameters().mutation.chanceOfTotalWeightReset)) {
		genome[index].SetRandomWeight();
	}
	else {
		PerturbWeightAt(index);
	}
}

auto NeuralNetwork::PerturbWeightAt(size_t index) -> void {
	constexpr float perturbanceBoundaries = 0.5f;
	auto perturbance = static_cast<float>(rand() % 10'000) / 9'999.0f * perturbanceBoundaries;
	if (rand() % 2) {
		perturbance = -perturbance;
	}
	genome[index].weight += perturbance;
	if (genome[index].weight < -1.0f) {
		genome[index].weight = -1.0f;
	}
	else if (genome[index].weight > 1.0f) {
		genome[index].weight = 1.0f;
	}
}

auto NeuralNetwork::MutateGenesAndBuildNetwork() -> void {
	if (ShouldAddConnection()) {
		BuildNetworkFromGenes();
		AddRandomConnection();
	}
	else {
		if (ShouldAddNeuron()) {
			AddRandomNeuron();
		} else {
			ShuffleWeights();
		}

		BuildNetworkFromGenes();
	}
}

auto NeuralNetwork::CategorizeNeuronsIntoLayers() -> void {
	for (auto i = 0U; i < GetTrainingParameters().structure.numberOfBiasNeurons; i++) {
		CategorizeNeuronBranchIntoLayers(neurons[i]);
	}
	for (auto* in : inputNeurons) {
		CategorizeNeuronBranchIntoLayers(*in);
	}

	size_t highestLayer = 0U;
	for (auto* out : outputNeurons) {
		highestLayer = max(out->GetLayer(), highestLayer);
	}
	for (auto* out : outputNeurons) {
		out->layer = highestLayer;
	}

	for (auto& neuron : neurons) {
		layerMap[neuron.GetLayer()].push_back(&neuron);
	}
}

auto NeuralNetwork::CategorizeNeuronBranchIntoLayers(Neuron& currNode, size_t currentDepth) const -> void {
	currNode.layer = currentDepth;
	const auto nextLayer = currNode.layer + 1;

	auto HasYetToBeLayered = [&nextLayer](const auto& connection) {
		return nextLayer > connection.neuron->layer;
	};
	auto IsInHigherLayer = [](const auto& connection) {
		return (connection.outGoing != connection.isRecursive);
	};

	for (auto &connection : currNode.GetConnections()) {
		if (HasYetToBeLayered(connection) && IsInHigherLayer(connection)) {
			CategorizeNeuronBranchIntoLayers(*connection.neuron, nextLayer);
		}
	}
}

auto NeuralNetwork::GetRandomEnabledGene() -> Gene& {
	size_t num = rand() % genome.GetGeneCount();
	auto randGene = genome.begin();
	randGene += num;
	while (randGene != genome.end() && !randGene->isEnabled) {
		++randGene;
	}
	if (randGene == genome.end()) {
		randGene = genome.begin() + num;
		while (randGene != genome.begin() && !randGene->isEnabled) {
			--randGene;
		}
	}
	if (!randGene->isEnabled) {
		throw runtime_error("Could not insert neuron because every gene is disabled");
	}
	return *randGene;
}

auto NeuralNetwork::GetJSON() const -> string {
	string s("{\"neurons\":[");
	for (size_t i = 0; i < neurons.size() - 1; ++i) {
		s += neurons[i].GetJSON();
		s += ",";
	}
	s += neurons.back().GetJSON();
	s += "],\"genome\":";
	s += genome.GetJSON();
	s += "}";
	return s;
}
<|endoftext|>


<commit_before>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "akonadidatasourcerepository.h"

#include "akonadiserializer.h"
#include "akonadistorage.h"
#include <QMenu>
#include <Akonadi/Calendar/StandardCalendarActionManager>
#include <Akonadi/EntityTreeModel>
#include <KActionCollection>
#include <KAction>
#include <KLocalizedString>
#include <QWidget>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <KCalCore/Todo>
#include <akonadi/notes/noteutils.h>
#include <akonadi/collectionpropertiesdialog.h>
#include <akonadi/attributefactory.h>
#include <pimcommon/acl/collectionaclpage.h>
#include <pimcommon/acl/imapaclattribute.h>

using namespace Akonadi;

DataSourceRepository::DataSourceRepository(QObject *parent)
    : QObject(parent),
      m_storage(new Storage),
      m_serializer(new Serializer),
      m_ownInterfaces(true)
{
}

DataSourceRepository::DataSourceRepository(StorageInterface *storage, SerializerInterface *serializer)
    : m_storage(storage),
      m_serializer(serializer),
      m_ownInterfaces(false)
{
}

DataSourceRepository::~DataSourceRepository()
{
    if (m_ownInterfaces) {
        delete m_storage;
        delete m_serializer;
    }
}

KJob *DataSourceRepository::update(Domain::DataSource::Ptr source)
{
    auto collection = m_serializer->createCollectionFromDataSource(source);
    Q_ASSERT(collection.isValid());
    return m_storage->updateCollection(collection);
}

void DataSourceRepository::configure(QMenu *menu , Domain::DataSource::Ptr selectedSource)
{
    {
        static bool pageRegistered = false;
        if (!pageRegistered) {
            kDebug() << "registering pages";
            Akonadi::AttributeFactory::registerAttribute<PimCommon::ImapAclAttribute>();
            // Akonadi::CollectionPropertiesDialog::registerPage(new CalendarSupport::CollectionGeneralPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
            pageRegistered = true;
        }
    }

    if (menu->isEmpty()) {
        //We bind the lifetime of all actions to the menu and simply recreate the menu everytime.
        QObject *parent = menu;
        //This can could be used to provide a parent widget for the created dialogs
        QWidget *parentWidget = 0;

        static auto actionCollection = new KActionCollection(0, KComponentData());
        //We can't delete the actionmanager because it's the parent of running jobs
        static Akonadi::StandardCalendarActionManager *mActionManager = 0;
        if (!mActionManager) {
            mActionManager = new Akonadi::StandardCalendarActionManager(actionCollection, parentWidget);

            QList<Akonadi::StandardActionManager::Type> standardActions;
            standardActions << Akonadi::StandardActionManager::CreateCollection
                            << Akonadi::StandardActionManager::DeleteCollections
                            << Akonadi::StandardActionManager::SynchronizeCollections
                            << Akonadi::StandardActionManager::CollectionProperties;

            Q_FOREACH(Akonadi::StandardActionManager::Type standardAction, standardActions) {
                mActionManager->createAction(standardAction);
            }

            const QStringList pages = QStringList() << QLatin1String("CalendarSupport::CollectionGeneralPage")
                                                    << QLatin1String("Akonadi::CachePolicyPage")
                                                    << QLatin1String("PimCommon::CollectionAclPage");
            mActionManager->setCollectionPropertiesPageNames(pages);
        }

        const auto collection = m_serializer->createCollectionFromDataSource(selectedSource);

        //FIXME set appropriate mimetypes based on selected source
        if (m_serializer->isTaskCollection(collection)) {
            mActionManager->setActionText(Akonadi::StandardActionManager::CreateCollection, ki18n("Add Task Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::DeleteCollections, ki18n("Delete Task Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollections, ki18n("Update Folder"));
            mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties,
                                            Akonadi::StandardActionManager::DialogTitle,
                                            tr("@title:window", "Properties of Task Folder %1"));
            mActionManager->action(Akonadi::StandardActionManager::CreateCollection )->setProperty("ContentMimeTypes",
                                        QStringList() << Akonadi::Collection::mimeType() << KCalCore::Todo::todoMimeType());
        } else if (m_serializer->isNoteCollection(collection)) {
            mActionManager->setActionText(Akonadi::StandardActionManager::CreateCollection, ki18n("Add Note Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::DeleteCollections, ki18n("Delete Note Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollections, ki18n("Update Folder"));
            mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties,
                                            Akonadi::StandardActionManager::DialogTitle,
                                            tr("@title:window", "Properties of Note Folder %1"));
            mActionManager->action(Akonadi::StandardActionManager::CreateCollection )->setProperty("ContentMimeTypes",
                                        QStringList() << Akonadi::Collection::mimeType() << Akonadi::NoteUtils::noteMimeType());
        }

        menu->addActions(actionCollection->actions());

        //Since we have no ETM based selection model we simply emulate one to tell the actionmanager about the current collection
        auto itemModel = new QStandardItemModel(parent);
        auto selectionModel = new QItemSelectionModel(itemModel);

        auto item = new QStandardItem();
        item->setData(QVariant::fromValue(collection), Akonadi::EntityTreeModel::CollectionRole);
        itemModel->setItem(0, 0, item);

        mActionManager->setCollectionSelectionModel(selectionModel);

        selectionModel->setCurrentIndex(itemModel->index(0, 0, QModelIndex()), QItemSelectionModel::SelectCurrent);
    } else {
        //update actions according to selected datasource
        //TODO currently we always recreate all actions and menues
    }
}
<commit_msg>Set collectionmodel before updating actions.<commit_after>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "akonadidatasourcerepository.h"

#include "akonadiserializer.h"
#include "akonadistorage.h"
#include <QMenu>
#include <Akonadi/Calendar/StandardCalendarActionManager>
#include <Akonadi/EntityTreeModel>
#include <KActionCollection>
#include <KAction>
#include <KLocalizedString>
#include <QWidget>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <KCalCore/Todo>
#include <akonadi/notes/noteutils.h>
#include <akonadi/collectionpropertiesdialog.h>
#include <akonadi/attributefactory.h>
#include <pimcommon/acl/collectionaclpage.h>
#include <pimcommon/acl/imapaclattribute.h>

using namespace Akonadi;

DataSourceRepository::DataSourceRepository(QObject *parent)
    : QObject(parent),
      m_storage(new Storage),
      m_serializer(new Serializer),
      m_ownInterfaces(true)
{
}

DataSourceRepository::DataSourceRepository(StorageInterface *storage, SerializerInterface *serializer)
    : m_storage(storage),
      m_serializer(serializer),
      m_ownInterfaces(false)
{
}

DataSourceRepository::~DataSourceRepository()
{
    if (m_ownInterfaces) {
        delete m_storage;
        delete m_serializer;
    }
}

KJob *DataSourceRepository::update(Domain::DataSource::Ptr source)
{
    auto collection = m_serializer->createCollectionFromDataSource(source);
    Q_ASSERT(collection.isValid());
    return m_storage->updateCollection(collection);
}

void DataSourceRepository::configure(QMenu *menu , Domain::DataSource::Ptr selectedSource)
{
    {
        static bool pageRegistered = false;
        if (!pageRegistered) {
            kDebug() << "registering pages";
            // Akonadi::CollectionPropertiesDialog::registerPage(new CalendarSupport::CollectionGeneralPageFactory);
            Akonadi::CollectionPropertiesDialog::registerPage(new PimCommon::CollectionAclPageFactory);
            pageRegistered = true;
        }
    }

    if (menu->isEmpty()) {
        //We bind the lifetime of all actions to the menu and simply recreate the menu everytime.
        QObject *parent = menu;
        //This can could be used to provide a parent widget for the created dialogs
        QWidget *parentWidget = 0;

        static auto actionCollection = new KActionCollection(0, KComponentData());
        //We can't delete the actionmanager because it's the parent of running jobs
        static Akonadi::StandardCalendarActionManager *mActionManager = 0;
        if (!mActionManager) {
            mActionManager = new Akonadi::StandardCalendarActionManager(actionCollection, parentWidget);

            QList<Akonadi::StandardActionManager::Type> standardActions;
            standardActions << Akonadi::StandardActionManager::CreateCollection
                            << Akonadi::StandardActionManager::DeleteCollections
                            << Akonadi::StandardActionManager::SynchronizeCollections
                            << Akonadi::StandardActionManager::CollectionProperties;

            Q_FOREACH(Akonadi::StandardActionManager::Type standardAction, standardActions) {
                mActionManager->createAction(standardAction);
            }

            const QStringList pages = QStringList() << QLatin1String("CalendarSupport::CollectionGeneralPage")
                                                    << QLatin1String("Akonadi::CachePolicyPage")
                                                    << QLatin1String("PimCommon::CollectionAclPage");
            mActionManager->setCollectionPropertiesPageNames(pages);
        }

        const auto collection = m_serializer->createCollectionFromDataSource(selectedSource);

        //Since we have no ETM based selection model we simply emulate one to tell the actionmanager about the current collection
        auto itemModel = new QStandardItemModel(parent);
        auto selectionModel = new QItemSelectionModel(itemModel);

        auto item = new QStandardItem();
        item->setData(QVariant::fromValue(collection), Akonadi::EntityTreeModel::CollectionRole);
        itemModel->setItem(0, 0, item);

        mActionManager->setCollectionSelectionModel(selectionModel);

        selectionModel->setCurrentIndex(itemModel->index(0, 0, QModelIndex()), QItemSelectionModel::SelectCurrent);

        //FIXME set appropriate mimetypes based on selected source
        if (m_serializer->isTaskCollection(collection)) {
            mActionManager->setActionText(Akonadi::StandardActionManager::CreateCollection, ki18n("Add Task Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::DeleteCollections, ki18n("Delete Task Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollections, ki18n("Update Folder"));
            mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties,
                                            Akonadi::StandardActionManager::DialogTitle,
                                            tr("@title:window", "Properties of Task Folder %1"));
            mActionManager->action(Akonadi::StandardActionManager::CreateCollection )->setProperty("ContentMimeTypes",
                                        QStringList() << Akonadi::Collection::mimeType() << KCalCore::Todo::todoMimeType());
        } else if (m_serializer->isNoteCollection(collection)) {
            mActionManager->setActionText(Akonadi::StandardActionManager::CreateCollection, ki18n("Add Note Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::DeleteCollections, ki18n("Delete Note Folder"));
            mActionManager->setActionText(Akonadi::StandardActionManager::SynchronizeCollections, ki18n("Update Folder"));
            mActionManager->setContextText(Akonadi::StandardActionManager::CollectionProperties,
                                            Akonadi::StandardActionManager::DialogTitle,
                                            tr("@title:window", "Properties of Note Folder %1"));
            mActionManager->action(Akonadi::StandardActionManager::CreateCollection )->setProperty("ContentMimeTypes",
                                        QStringList() << Akonadi::Collection::mimeType() << Akonadi::NoteUtils::noteMimeType());
        }

        menu->addActions(actionCollection->actions());
    } else {
        //update actions according to selected datasource
        //TODO currently we always recreate all actions and menues
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "autocorrelation.h"
#include "essentiamath.h"

using namespace std;
using namespace essentia;
using namespace standard;

const char* AutoCorrelation::name = "AutoCorrelation";
const char* AutoCorrelation::category = "Standard";
const char* AutoCorrelation::description = DOC(
"This algorithm computes the autocorrelation vector of a signal.\n"
"It uses the version most commonly used in signal processing, which doesn't remove "
"the mean from the observations.\n"
"Using the 'generalized' option this algorithm computes autocorrelation as described in [3].\n"
"\n"
"References:\n"
"  [1] Autocorrelation -- from Wolfram MathWorld,\n"
"  http://mathworld.wolfram.com/Autocorrelation.html\n\n"
"  [2] Autocorrelation - Wikipedia, the free encyclopedia,\n"
"  http://en.wikipedia.org/wiki/Autocorrelation\n\n"
"  [3] Tolonen T., and Karjalainen, M. (2000). A computationally efficient multipitch analysis model.\n"
"  IEEE Transactions on Audio, Speech, and Language Processing, 8(6), 708-716.\n\n"
);

void AutoCorrelation::configure() {
  string ntype = parameter("normalization").toString();

  if (ntype == "standard") {
    _unbiasedNormalization = false;
  }
  else if (ntype == "unbiased") {
    _unbiasedNormalization = true;
  }

  _generalized = parameter("generalized").toBool();
  _frequencyDomainCompression = parameter("frequencyDomainCompression").toReal();

  _fft->output("fft").set(_fftBuffer);
  _ifft->input("fft").set(_fftBuffer);
}

void AutoCorrelation::compute() {

  const std::vector<Real>& signal = _signal.get();
  vector<Real>& correlation = _correlation.get();

  if (signal.size() == 0) {
    correlation.resize(0);
    return;
  }

  _fft->input("frame").set(_paddedSignal);
  _ifft->output("frame").set(_corr);

  int size = int(signal.size());
  int sizeFFT = int(nextPowerTwo(2*size));

  // formula to get the auto-correlation (in matlab) is:
  //  [M,N] = size(x)
  //  X = fft(x,2^nextpow2(2*M-1));
  //  c = ifft(abs(X).^2);

  // copy signal, and zero-pad it; use _corr as temporary array
  _paddedSignal.resize(sizeFFT);
  for (int i=0; i<size; i++) _paddedSignal[i] = signal[i];
  for (int i=size; i<sizeFFT; i++) _paddedSignal[i] = 0.0;

  // first compute fft
  _fft->compute();

  // take squared amplitude of the spectrum
  // (using magnitude would compute sqrt*sqrt)
  for (int i=0; i<int(_fftBuffer.size()); i++) {
    if (!_generalized){
      _fftBuffer[i] = complex<Real>(_fftBuffer[i].real() * _fftBuffer[i].real() +
                                    _fftBuffer[i].imag() * _fftBuffer[i].imag(), // Generalized, todo 0.5 -> c
                                    0.0); // squared amplitude -> complex part = 0
    } else {
      // Apply magnitude compression
      _fftBuffer[i] = complex<Real>(
        pow(sqrt(pow(_fftBuffer[i].real() / sizeFFT, 2) + pow(_fftBuffer[i].imag() / sizeFFT, 2)), _frequencyDomainCompression),
        0.0); // squared amplitude -> complex part = 0
    }
  }

  // step 3
  _ifft->compute();

  // copy results in output array, scaling on the go (normalizing the output of the IFFT)
  Real scale = 1.0 / sizeFFT;
  if (_generalized) {
    scale = sizeFFT * scale;
  }
  correlation.resize(size);

  if (_unbiasedNormalization) {
    for (int i=0; i<size; i++) {
      correlation[i] = _corr[i] * scale / (size - i);
    }
  }
  else {
    for (int i=0; i<size; i++) {
      correlation[i] = _corr[i] * scale;
    }
  }
}
<commit_msg>Simplify Autocorrelation code<commit_after>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "autocorrelation.h"
#include "essentiamath.h"

using namespace std;
using namespace essentia;
using namespace standard;

const char* AutoCorrelation::name = "AutoCorrelation";
const char* AutoCorrelation::category = "Standard";
const char* AutoCorrelation::description = DOC(
"This algorithm computes the autocorrelation vector of a signal.\n"
"It uses the version most commonly used in signal processing, which doesn't remove "
"the mean from the observations.\n"
"Using the 'generalized' option this algorithm computes autocorrelation as described in [3].\n"
"\n"
"References:\n"
"  [1] Autocorrelation -- from Wolfram MathWorld,\n"
"  http://mathworld.wolfram.com/Autocorrelation.html\n\n"
"  [2] Autocorrelation - Wikipedia, the free encyclopedia,\n"
"  http://en.wikipedia.org/wiki/Autocorrelation\n\n"
"  [3] Tolonen T., and Karjalainen, M. (2000). A computationally efficient multipitch analysis model.\n"
"  IEEE Transactions on Audio, Speech, and Language Processing, 8(6), 708-716.\n\n"
);

void AutoCorrelation::configure() {
  string ntype = parameter("normalization").toString();

  if (ntype == "standard") {
    _unbiasedNormalization = false;
  }
  else if (ntype == "unbiased") {
    _unbiasedNormalization = true;
  }

  _generalized = parameter("generalized").toBool();
  _frequencyDomainCompression = parameter("frequencyDomainCompression").toReal();

  _ifft->configure("normalize", !_generalized);

  _fft->output("fft").set(_fftBuffer);
  _ifft->input("fft").set(_fftBuffer);
}

void AutoCorrelation::compute() {

  const std::vector<Real>& signal = _signal.get();
  vector<Real>& correlation = _correlation.get();

  if (signal.size() == 0) {
    correlation.resize(0);
    return;
  }

  _fft->input("frame").set(_paddedSignal);
  _ifft->output("frame").set(_corr);

  int size = int(signal.size());
  int sizeFFT = int(nextPowerTwo(2*size));

  // formula to get the auto-correlation (in matlab) is:
  //  [M,N] = size(x)
  //  X = fft(x,2^nextpow2(2*M-1));
  //  c = ifft(abs(X).^2);

  // copy signal, and zero-pad it; use _corr as temporary array
  _paddedSignal.resize(sizeFFT);
  for (int i=0; i<size; i++) _paddedSignal[i] = signal[i];
  for (int i=size; i<sizeFFT; i++) _paddedSignal[i] = 0.0;

  // first compute fft
  _fft->compute();

  // take squared amplitude of the spectrum
  // (using magnitude would compute sqrt*sqrt)
  for (int i=0; i<int(_fftBuffer.size()); i++) {
    if (!_generalized){
      _fftBuffer[i] = complex<Real>(_fftBuffer[i].real() * _fftBuffer[i].real() +
                                    _fftBuffer[i].imag() * _fftBuffer[i].imag(), // Generalized, todo 0.5 -> c
                                    0.0); // squared amplitude -> complex part = 0
    } else {
      // Apply magnitude compression
      _fftBuffer[i] = complex<Real>(
        pow(sqrt(pow(_fftBuffer[i].real() / sizeFFT, 2) + pow(_fftBuffer[i].imag() / sizeFFT, 2)), _frequencyDomainCompression),
        0.0); // squared amplitude -> complex part = 0
    }
  }

  // step 3
  _ifft->compute();

  // copy results in output array, scaling on the go (normalizing the output of the IFFT)
  correlation.resize(size);

  if (_unbiasedNormalization) {
    for (int i=0; i<size; i++) {
      correlation[i] = _corr[i] / (size - i);
    }
  }
  else {
    for (int i=0; i<size; i++) {
      correlation[i] = _corr[i];
    }
  }
}
<|endoftext|>


<commit_before>/*
 * ProgramTest.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <cassert>
#include <fstream>
#include <sstream>
#include <boost/filesystem.hpp>
#include <GL/glfw.h>
#include "glycerin/common.h"
#include "glycerin/shader/Program.hpp"
using namespace std;
using namespace Glycerin;
namespace bfs = boost::filesystem;

const char* VERTEX_SHADER =
        "#version 140\n"
        "uniform mat4 MVPMatrix = mat4(1);\n"
        "in vec4 MCVertex;\n"
        "void main() {\n"
        "    gl_Position = MVPMatrix * MCVertex;\n"
        "}\n";

const char* FRAGMENT_SHADER =
        "#version 140\n"
        "uniform vec4 Color = vec4(1);\n"
        "out vec4 FragColor;\n"
        "void main() {\n"
        "    FragColor = Color;\n"
        "}\n";

/**
 * Unit test for Program.
 */
class ProgramTest {
public:

    /**
     * Ensures Program links with a vertex and fragment shader.
     */
    void testLinkWithVertexAndFragmentShader() {

        // Create a program
        Program program = Program::create();
        assert (program.handle() > 0);

        // Create shaders
        Shader vs = Shader::create(GL_VERTEX_SHADER);
        vs.source(VERTEX_SHADER);
        vs.compile();
        Shader fs = Shader::create(GL_FRAGMENT_SHADER);
        fs.source(FRAGMENT_SHADER);
        fs.compile();

        // Add the shaders to the program
        program.attachShader(vs);
        program.attachShader(fs);

        // Delete the shaders
        vs.dispose();
        fs.dispose();

        // Link the program
        program.link();
        if (!program.linked()) {
            cerr << program.log() << endl;
            throw runtime_error("Could not link program!");
        }

        // Validate it
        program.validate();
        if (!program.valid()) {
            cerr << program.log() << endl;
            throw runtime_error("Could not validate program!");
        }

        // Delete it
        program.dispose();
    }
};

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

    // Capture the initial working directory before GLFW changes it
    bfs::path dir = bfs::initial_path();

    // Initialize GLFW
    if (!glfwInit()) {
        cerr << "Could not initialize GLFW!" << endl;
        return 1;
    }

    // Reset current directory
    bfs::current_path(dir);

    // Open a window
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwOpenWindow(512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW);

    // Run the test
    ProgramTest test;
    try {
        test.testLinkWithVertexAndFragmentShader();
    } catch (exception& e) {
        cerr << e.what() << endl;
        throw;
    }

    // Exit
    glfwTerminate();
    return 0;
}
<commit_msg>Program test case with bad shaders (ref #15)<commit_after>/*
 * ProgramTest.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <cassert>
#include <fstream>
#include <sstream>
#include <boost/filesystem.hpp>
#include <GL/glfw.h>
#include "glycerin/common.h"
#include "glycerin/shader/Program.hpp"
using namespace std;
using namespace Glycerin;
namespace bfs = boost::filesystem;

const char* BAD_VERTEX_SHADER =
        "#version 140\n"
        "in vec4 MCVertex;\n"
        "void main() {\n"
        "    gl_position = MCVertex;\n"
        "}\n";

const char* BAD_FRAGMENT_SHADER =
        "#version 140\n"
        "out vec4 FragColor;\n"
        "void main() {\n"
        "    fragColor = vec4(1);\n"
        "}\n";

const char* GOOD_VERTEX_SHADER =
        "#version 140\n"
        "uniform mat4 MVPMatrix = mat4(1);\n"
        "in vec4 MCVertex;\n"
        "void main() {\n"
        "    gl_Position = MVPMatrix * MCVertex;\n"
        "}\n";

const char* GOOD_FRAGMENT_SHADER =
        "#version 140\n"
        "uniform vec4 Color = vec4(1);\n"
        "out vec4 FragColor;\n"
        "void main() {\n"
        "    FragColor = Color;\n"
        "}\n";

/**
 * Unit test for Program.
 */
class ProgramTest {
public:

    /**
     * Ensures Program links with a vertex and fragment shader.
     */
    void testLinkWithGoodVertexAndFragmentShader() {

        // Create a program
        Program program = Program::create();
        assert (program.handle() > 0);

        // Create shaders
        Shader vs = Shader::create(GL_VERTEX_SHADER);
        vs.source(GOOD_VERTEX_SHADER);
        vs.compile();
        Shader fs = Shader::create(GL_FRAGMENT_SHADER);
        fs.source(GOOD_FRAGMENT_SHADER);
        fs.compile();

        // Add the shaders to the program
        program.attachShader(vs);
        program.attachShader(fs);

        // Delete the shaders
        vs.dispose();
        fs.dispose();

        // Link the program
        program.link();
        if (!program.linked()) {
            cerr << program.log() << endl;
            throw runtime_error("Could not link program!");
        }

        // Validate it
        program.validate();
        if (!program.valid()) {
            cerr << program.log() << endl;
            throw runtime_error("Could not validate program!");
        }

        // Delete it
        program.dispose();
    }

    /**
     * Ensures Program does not link and validate with a bad vertex and fragment shader.
     */
    void testLinkWithBadVertexAndFragmentShader() {

        // Create a program
        Program program = Program::create();
        assert (program.handle() > 0);

        // Create shaders
        Shader vs = Shader::create(GL_VERTEX_SHADER);
        vs.source(BAD_VERTEX_SHADER);
        vs.compile();
        Shader fs = Shader::create(GL_FRAGMENT_SHADER);
        fs.source(BAD_FRAGMENT_SHADER);
        fs.compile();

        // Add the shaders to the program
        program.attachShader(vs);
        program.attachShader(fs);

        // Delete the shaders
        vs.dispose();
        fs.dispose();

        // Link the program
        program.link();
        if (program.linked()) {
            throw runtime_error("Linked bad program!");
        }

        // Delete it
        program.dispose();
    }
};

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

    // Capture the initial working directory before GLFW changes it
    bfs::path dir = bfs::initial_path();

    // Initialize GLFW
    if (!glfwInit()) {
        cerr << "Could not initialize GLFW!" << endl;
        return 1;
    }

    // Reset current directory
    bfs::current_path(dir);

    // Open a window
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwOpenWindow(512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW);

    // Run the test
    ProgramTest test;
    try {
        test.testLinkWithGoodVertexAndFragmentShader();
        test.testLinkWithBadVertexAndFragmentShader();
    } catch (exception& e) {
        cerr << e.what() << endl;
        throw;
    }

    // Exit
    glfwTerminate();
    return 0;
}
<|endoftext|>


<commit_before>#include "graphic_system.hpp"

#include <core/units.hpp>

#include "../physics/physics_comp.hpp"

namespace mo {
namespace sys {
namespace graphic {

	using namespace renderer;
	using namespace unit_literals;

	namespace {
		bool is_lazy_particle(Effect_type t) {
			switch(t) {
				case Effect_type::none:              return true;
				case Effect_type::element_fire:      return true;
				case Effect_type::element_frost:     return true;
				case Effect_type::element_water:     return true;
				case Effect_type::element_stone:     return true;
				case Effect_type::element_gas:       return true;
				case Effect_type::element_lightning: return true;
				case Effect_type::health:            return true;

				case Effect_type::flame_thrower:     return false;
			}
		}
	}

	Graphic_system::Graphic_system(
	        ecs::Entity_manager& entity_manager,
	        sys::physics::Transform_system& ts,
	        asset::Asset_manager& asset_manager,
	        renderer::Particle_renderer& particle_renderer,
	        state::State_system& state_system) noexcept
		: effects(&Graphic_system::add_effect, this),
	      _assets(asset_manager),
	      _particle_renderer(particle_renderer),
	      _transform(ts),
	      _sprite_batch(asset_manager),
	      _sprites(entity_manager.list<Sprite_comp>()),
	      _particles(entity_manager.list<Particle_emiter_comp>()),
	      _state_change_slot(&Graphic_system::_on_state_change, this)
	{
		_state_change_slot.connect(state_system.state_change_events);

		entity_manager.register_component_type<Sprite_comp>();
		entity_manager.register_component_type<Particle_emiter_comp>();
	}

	void Graphic_system::add_effect(ecs::Entity& entity, Effect_type type) {
		auto emiter_m = entity.get<Particle_emiter_comp>();
		auto& emiter = emiter_m.is_some() ? emiter_m.get_or_throw()
		                                  : entity.emplace<Particle_emiter_comp>();

		for(auto i : util::range(Particle_emiter_comp::max_emiters)) {
			auto& e = emiter._emiters[i];
			if(e._type==type) {
				emiter.particle_type(i, type, false);
				emiter.enabled(i, true, true);
				return;
			}
		}

		for(auto i : util::range(Particle_emiter_comp::max_emiters)) {
			auto& e = emiter._emiters[i];
			if(!e._enabled) {
				emiter.particle_type(i, type, false);
				emiter.enabled(i, true, true);
				return;
			}
		}
	}

	void Graphic_system::draw(const renderer::Camera& camera) noexcept{
		glm::vec2 upper_left = camera.screen_to_world({camera.viewport().x, camera.viewport().y});
		glm::vec2 lower_right = camera.screen_to_world({camera.viewport().z, camera.viewport().w});

		_transform.foreach_in_rect(upper_left, lower_right, [&](ecs::Entity& entity) {
			process(entity.get<physics::Transform_comp>(),
	                entity.get<Sprite_comp>())
            >> [&](const auto& trans, const auto& sp) {
				auto sprite = sp.sprite();
				sprite.position = trans.position();
				sprite.layer = trans.layer();
				sprite.rotation = trans.rotation();
				_sprite_batch.draw(camera, sprite);
	        };
		});

		_sprite_batch.drawAll(camera);
	}

	void Graphic_system::update(Time dt) noexcept{
		for(auto& sprite : _sprites) {
			sprite.current_frame(
				sprite._animation->next_frame(
					sprite.animation_type(), sprite.current_frame(), dt.value(), sprite._repeat_animation
				)
			);
		}

		for(auto& p : _particles) {
			int i = -1;
			for(auto& e : p._emiters) {
				i++;
				if(!e._enabled)
					continue;

				_create_emiter(e);
				if(!e._emiter)
					continue;

				auto transform = p.owner().get<physics::Transform_comp>();
				auto physics = p.owner().get<physics::Physics_comp>();

				transform.process([&](auto& t) {
					auto vel = Velocity{0,0};
					if(!is_lazy_particle(e._type))
						vel = physics.process(vel, [](auto& p){return p.velocity();});

					e._emiter->update_center(t.position(), t.rotation(), vel);
				});

				if(e._scale) {
					physics.process([&](auto& phys){
						p.scale(i, phys.radius());
					});
				}

				if(e._temporary) {
					if(e._to_be_disabled)
						p.enabled(i, false);
					else
						e._to_be_disabled = true;
				}
			}
		}
	}

	namespace {
		Particle_emiter_ptr create_orb_emiter(Texture_ptr tex,
		                                      Particle_renderer& particle_renderer) {
			if(tex) {
				return particle_renderer.create_emiter(
						{0_m,0_m},
						0_deg,
						0.5_m,
						0_m,
						renderer::Collision_handler::none,
						100,
						200,
						0.05_s, 0.1_s,
						util::scerp<Angle>(0_deg, 0_deg),
						util::scerp<Angle>(0_deg, 0_deg),
						util::lerp<Speed_per_time>(8_m/second_2, 0_m/second_2),
						util::lerp<Angle_acceleration>(3000_deg/second_2, 0_deg/second_2),
						util::lerp<glm::vec4>({0.6,0.6,0.6,0}, {0,0,0,0.0}),
						util::lerp<Position>({25_cm, 25_cm}, {60_cm, 60_cm}, {2_cm, 2_cm}),
						util::scerp<int8_t>(0),
						tex
				);
			}

			return {};
		}

		Texture_ptr load_tex(asset::Asset_manager& a, std::string tex_name) {
			return a.load<renderer::Texture>(asset::AID(
					asset::Asset_type::tex, std::move(tex_name)));
		}
	}

	void Graphic_system::_create_emiter(Particle_emiter_comp::Emiter& e) {
		if(!e._emiter && e._enabled) {
			switch(e._type) {
				case Effect_type::none:
					e._enabled = false;
					return;

				case Effect_type::element_fire:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_fire"),
					                              _particle_renderer);
					break;
				case Effect_type::element_frost:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_frost"),
					                              _particle_renderer);
					break;
				case Effect_type::element_water:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_water"),
					                              _particle_renderer);
					break;
				case Effect_type::element_stone:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_stone"),
					                              _particle_renderer);
					break;
				case Effect_type::element_gas:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_gas"),
					                              _particle_renderer);
					break;
				case Effect_type::element_lightning:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_lightning"),
					                              _particle_renderer);
					break;
				case Effect_type::health:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_health"),
					                              _particle_renderer);
					break;

				case Effect_type::flame_thrower:
					e._emiter = _particle_renderer.create_emiter(
							{0_m,0_m},
							0_deg,
							0.01_m,
							0.55_m,
							renderer::Collision_handler::bounce,
							400,
							500,
							1.0_s, 1.2_s,
							util::scerp<Angle>(0_deg, 15_deg),
							util::scerp<Angle>(0_deg, 0_deg),
							util::lerp<Speed_per_time>(10_m/second_2, 0_m/second_2),
							util::scerp<Angle_acceleration>(0_deg/second_2, 5_deg/second_2),
							util::lerp<glm::vec4>({1,0.5,0.5,0}, {0,0,0,0.5}),
							util::lerp<Position>({20_cm, 20_cm}, {100_cm, 100_cm}, {10_cm, 10_cm}),
							util::scerp<int8_t>(0),
							load_tex(_assets,"particle_fire")
					);
					break;

					// TODO
			}
		}
	}

	void Graphic_system::_on_state_change(ecs::Entity& entity, state::State_data& data){

		entity.get<Sprite_comp>().process([&](Sprite_comp& sprite) {
			bool toRepeat = false;
			renderer::Animation_type type;

			// Map Entity-State to Animation-Type
			switch(data.s){
				case state::Entity_state::idle:
					type = renderer::Animation_type::idle;
					toRepeat = true;
					break;
				case state::Entity_state::walking:
					type = renderer::Animation_type::walking;
					toRepeat = true;
					break;
				case state::Entity_state::attacking_melee:
					type = renderer::Animation_type::attacking_melee;
					toRepeat = false;
					break;
				case state::Entity_state::attacking_range:
					type = renderer::Animation_type::attacking_range;
					toRepeat = true;
					break;
				case state::Entity_state::change_weapon:
					type = renderer::Animation_type::change_weapon;
					toRepeat = false;
					break;
				case state::Entity_state::taking:
					type = renderer::Animation_type::taking;
					toRepeat = false;
					break;
				case state::Entity_state::interacting:
					type = renderer::Animation_type::interacting;
					toRepeat = false;
					break;
				case state::Entity_state::damaged:
					type = renderer::Animation_type::damaged;
					toRepeat = false;
					break;
				case state::Entity_state::healed:
					type = renderer::Animation_type::healed;
					toRepeat = false;
					break;
				case state::Entity_state::dead:
					type = renderer::Animation_type::died;
					toRepeat = true;
					break;
				case state::Entity_state::dying:
					type = renderer::Animation_type::died; // TODO[seb]: dying? last frame from died?
					toRepeat = false;
					break;
				case state::Entity_state::resurrected:
					type = renderer::Animation_type::resurrected;
					toRepeat = false;
					break;
				default:
					type = renderer::Animation_type::idle;
					toRepeat = false;
					break;
			}

			// applying new animation type
			sprite._repeat_animation = toRepeat;
			sprite.animation_type(type);

			// applying magnitude
			sprite.animation()->modulation(type, data.magnitude);

			// calculating remaining time for current animation and inform state_comp about it
			data.min_time(sprite.animation()->remaining_time(sprite.animation_type(), sprite.current_frame()));
		});
	}

}
}
}
<commit_msg>Fixes for Windows Environment<commit_after>#include "graphic_system.hpp"

#include <core/units.hpp>

#include "../physics/physics_comp.hpp"

namespace mo {
namespace sys {
namespace graphic {

	using namespace renderer;
	using namespace unit_literals;

	namespace {
		bool is_lazy_particle(Effect_type t) {
			switch(t) {
				case Effect_type::none:              return true;
				case Effect_type::element_fire:      return true;
				case Effect_type::element_frost:     return true;
				case Effect_type::element_water:     return true;
				case Effect_type::element_stone:     return true;
				case Effect_type::element_gas:       return true;
				case Effect_type::element_lightning: return true;
				case Effect_type::health:            return true;

				case Effect_type::flame_thrower:     return false;
			}
            FAIL("UNREACHABLE, maybe");
		}
	}

	Graphic_system::Graphic_system(
	        ecs::Entity_manager& entity_manager,
	        sys::physics::Transform_system& ts,
	        asset::Asset_manager& asset_manager,
	        renderer::Particle_renderer& particle_renderer,
	        state::State_system& state_system) noexcept
		: effects(&Graphic_system::add_effect, this),
	      _assets(asset_manager),
	      _particle_renderer(particle_renderer),
	      _transform(ts),
	      _sprite_batch(asset_manager),
	      _sprites(entity_manager.list<Sprite_comp>()),
	      _particles(entity_manager.list<Particle_emiter_comp>()),
	      _state_change_slot(&Graphic_system::_on_state_change, this)
	{
		_state_change_slot.connect(state_system.state_change_events);

		entity_manager.register_component_type<Sprite_comp>();
		entity_manager.register_component_type<Particle_emiter_comp>();
	}

	void Graphic_system::add_effect(ecs::Entity& entity, Effect_type type) {
		auto emiter_m = entity.get<Particle_emiter_comp>();
		auto& emiter = emiter_m.is_some() ? emiter_m.get_or_throw()
		                                  : entity.emplace<Particle_emiter_comp>();

		for(auto i : util::range(Particle_emiter_comp::max_emiters)) {
			auto& e = emiter._emiters[i];
			if(e._type==type) {
				emiter.particle_type(i, type, false);
				emiter.enabled(i, true, true);
				return;
			}
		}

		for(auto i : util::range(Particle_emiter_comp::max_emiters)) {
			auto& e = emiter._emiters[i];
			if(!e._enabled) {
				emiter.particle_type(i, type, false);
				emiter.enabled(i, true, true);
				return;
			}
		}
	}

	void Graphic_system::draw(const renderer::Camera& camera) noexcept{
		glm::vec2 upper_left = camera.screen_to_world({camera.viewport().x, camera.viewport().y});
		glm::vec2 lower_right = camera.screen_to_world({camera.viewport().z, camera.viewport().w});

		_transform.foreach_in_rect(upper_left, lower_right, [&](ecs::Entity& entity) {
			process(entity.get<physics::Transform_comp>(),
	                entity.get<Sprite_comp>())
            >> [&](const auto& trans, const auto& sp) {
				auto sprite = sp.sprite();
				sprite.position = trans.position();
				sprite.layer = trans.layer();
				sprite.rotation = trans.rotation();
				_sprite_batch.draw(camera, sprite);
	        };
		});

		_sprite_batch.drawAll(camera);
	}

	void Graphic_system::update(Time dt) noexcept{
		for(auto& sprite : _sprites) {
			sprite.current_frame(
				sprite._animation->next_frame(
					sprite.animation_type(), sprite.current_frame(), dt.value(), sprite._repeat_animation
				)
			);
		}

		for(auto& p : _particles) {
			int i = -1;
			for(auto& e : p._emiters) {
				i++;
				if(!e._enabled)
					continue;

				_create_emiter(e);
				if(!e._emiter)
					continue;

				auto transform = p.owner().get<physics::Transform_comp>();
				auto physics = p.owner().get<physics::Physics_comp>();

				transform.process([&](auto& t) {
					auto vel = Velocity{0,0};
					if(!is_lazy_particle(e._type))
						vel = physics.process(vel, [](auto& p){return p.velocity();});

					e._emiter->update_center(t.position(), t.rotation(), vel);
				});

				if(e._scale) {
					physics.process([&](auto& phys){
						p.scale(i, phys.radius());
					});
				}

				if(e._temporary) {
					if(e._to_be_disabled)
						p.enabled(i, false);
					else
						e._to_be_disabled = true;
				}
			}
		}
	}

	namespace {
		Particle_emiter_ptr create_orb_emiter(Texture_ptr tex,
		                                      Particle_renderer& particle_renderer) {
			if(tex) {
				return particle_renderer.create_emiter(
						{0_m,0_m},
						0_deg,
						0.5_m,
						0_m,
						renderer::Collision_handler::none,
						100,
						200,
						0.05_s, 0.1_s,
						util::scerp<Angle>(0_deg, 0_deg),
						util::scerp<Angle>(0_deg, 0_deg),
						util::lerp<Speed_per_time>(8_m/second_2, 0_m/second_2),
						util::lerp<Angle_acceleration>(3000_deg/second_2, 0_deg/second_2),
						util::lerp<glm::vec4>({0.6,0.6,0.6,0}, {0,0,0,0.0}),
						util::lerp<Position>({25_cm, 25_cm}, {60_cm, 60_cm}, {2_cm, 2_cm}),
						util::scerp<int8_t>(0),
						tex
				);
			}

			return {};
		}

		Texture_ptr load_tex(asset::Asset_manager& a, std::string tex_name) {
			return a.load<renderer::Texture>(asset::AID(
					asset::Asset_type::tex, std::move(tex_name)));
		}
	}

	void Graphic_system::_create_emiter(Particle_emiter_comp::Emiter& e) {
		if(!e._emiter && e._enabled) {
			switch(e._type) {
				case Effect_type::none:
					e._enabled = false;
					return;

				case Effect_type::element_fire:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_fire"),
					                              _particle_renderer);
					break;
				case Effect_type::element_frost:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_frost"),
					                              _particle_renderer);
					break;
				case Effect_type::element_water:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_water"),
					                              _particle_renderer);
					break;
				case Effect_type::element_stone:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_stone"),
					                              _particle_renderer);
					break;
				case Effect_type::element_gas:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_gas"),
					                              _particle_renderer);
					break;
				case Effect_type::element_lightning:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_lightning"),
					                              _particle_renderer);
					break;
				case Effect_type::health:
					e._emiter = create_orb_emiter(load_tex(_assets,"particle_health"),
					                              _particle_renderer);
					break;

				case Effect_type::flame_thrower:
					e._emiter = _particle_renderer.create_emiter(
							{0_m,0_m},
							0_deg,
							0.01_m,
							0.55_m,
							renderer::Collision_handler::bounce,
							400,
							500,
							1.0_s, 1.2_s,
							util::scerp<Angle>(0_deg, 15_deg),
							util::scerp<Angle>(0_deg, 0_deg),
							util::lerp<Speed_per_time>(10_m/second_2, 0_m/second_2),
							util::scerp<Angle_acceleration>(0_deg/second_2, 5_deg/second_2),
							util::lerp<glm::vec4>({1,0.5,0.5,0}, {0,0,0,0.5}),
							util::lerp<Position>({20_cm, 20_cm}, {100_cm, 100_cm}, {10_cm, 10_cm}),
							util::scerp<int8_t>(0),
							load_tex(_assets,"particle_fire")
					);
					break;

					// TODO
			}
		}
	}

	void Graphic_system::_on_state_change(ecs::Entity& entity, state::State_data& data){

		entity.get<Sprite_comp>().process([&](Sprite_comp& sprite) {
			bool toRepeat = false;
			renderer::Animation_type type;

			// Map Entity-State to Animation-Type
			switch(data.s){
				case state::Entity_state::idle:
					type = renderer::Animation_type::idle;
					toRepeat = true;
					break;
				case state::Entity_state::walking:
					type = renderer::Animation_type::walking;
					toRepeat = true;
					break;
				case state::Entity_state::attacking_melee:
					type = renderer::Animation_type::attacking_melee;
					toRepeat = false;
					break;
				case state::Entity_state::attacking_range:
					type = renderer::Animation_type::attacking_range;
					toRepeat = true;
					break;
				case state::Entity_state::change_weapon:
					type = renderer::Animation_type::change_weapon;
					toRepeat = false;
					break;
				case state::Entity_state::taking:
					type = renderer::Animation_type::taking;
					toRepeat = false;
					break;
				case state::Entity_state::interacting:
					type = renderer::Animation_type::interacting;
					toRepeat = false;
					break;
				case state::Entity_state::damaged:
					type = renderer::Animation_type::damaged;
					toRepeat = false;
					break;
				case state::Entity_state::healed:
					type = renderer::Animation_type::healed;
					toRepeat = false;
					break;
				case state::Entity_state::dead:
					type = renderer::Animation_type::died;
					toRepeat = true;
					break;
				case state::Entity_state::dying:
					type = renderer::Animation_type::died; // TODO[seb]: dying? last frame from died?
					toRepeat = false;
					break;
				case state::Entity_state::resurrected:
					type = renderer::Animation_type::resurrected;
					toRepeat = false;
					break;
				default:
					type = renderer::Animation_type::idle;
					toRepeat = false;
					break;
			}

			// applying new animation type
			sprite._repeat_animation = toRepeat;
			sprite.animation_type(type);

			// applying magnitude
			sprite.animation()->modulation(type, data.magnitude);

			// calculating remaining time for current animation and inform state_comp about it
			data.min_time(sprite.animation()->remaining_time(sprite.animation_type(), sprite.current_frame()));
		});
	}

}
}
}
<|endoftext|>


<commit_before>//******************************************************************************
// FILE : function_variable.hpp
//
// LAST MODIFIED : 23 January 2005
//
// DESCRIPTION :
// An abstract class for specifying input/independent and output/dependent
// variables of a function.
//
// Function_variables can be evaluated, differentiated or set to another value.
//==============================================================================
#if !defined (__FUNCTION_VARIABLE_HPP__)
#define __FUNCTION_VARIABLE_HPP__

#include <iterator>
#include <list>

#include "computed_variable/function_base.hpp"
#include "computed_variable/function_variable_value.hpp"

//#define USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE

class Function_variable_iterator_representation
//******************************************************************************
// LAST MODIFIED : 2 March 2004
//
// DESCRIPTION :
//
// NOTES:
// To get iterators for a sub-class of Function_variable, derive a represenation
// class from this one.
//==============================================================================
{
	friend class Function_variable_iterator;
	public:
		// a "virtual" constructor
		virtual Function_variable_iterator_representation *clone()=0;
	protected:
		// destructor.  Virtual for proper destruction of derived classes
		virtual ~Function_variable_iterator_representation();
	private:
		// increment.  Do not want to return an object derived from
		//   Function_variable_iterator_representation.  Used by
		//   Function_variable_iterator::operator++() and ++(int)
		virtual void increment()=0;
		// decrement.  Do not want to return an object derived from
		//   Function_variable_iterator_representation.  Needs to be able to step
		//   from one past the last to the last.  Used by
		//   Function_variable_iterator::operator--() and --(int)
		virtual void decrement()=0;
		// equality.  Used by Function_variable_iterator::operator==() and !=()
		virtual bool equality(const Function_variable_iterator_representation*)=0;
		// dereference.  Used by Function_variable_iterator::operator*()
		virtual Function_variable_handle dereference() const=0;
	protected:
		// constructor.  Protected so that can't create "plain"
		//   Function_variable_iterator_representations
		Function_variable_iterator_representation();
	private:
		// copy operations are private and undefined to prevent copying
		Function_variable_iterator_representation(
			const Function_variable_iterator_representation&);
		Function_variable_iterator_representation& operator=(
			const Function_variable_iterator_representation&);
};

class Function_variable_iterator:
	public std::iterator<std::bidirectional_iterator_tag,Function_variable_handle,
	ptrdiff_t,Function_variable_handle*,Function_variable_handle>
//******************************************************************************
// LAST MODIFIED : 2 March 2004
//
// DESCRIPTION :
//
// NOTES:
// Do not derive from this class.  Derive from
// Function_variable_iterator_representation.
//
// The reference is Function_variable_handle rather the
// Function_variable_handle& (the default for std::iterator<>) because using
// smart pointers and because the objects in the pool being iterated are created
// by the iterator as required.
//==============================================================================
{
	public:
		// constructors
		Function_variable_iterator();
		Function_variable_iterator(Function_variable_iterator_representation *);
		// copy constructor
		Function_variable_iterator(const Function_variable_iterator&);
		// assignment
		Function_variable_iterator& operator=(const Function_variable_iterator&);
		// destructor
		~Function_variable_iterator();
		// increment (prefix)
		Function_variable_iterator& operator++();
		// increment (postfix)
		Function_variable_iterator operator++(int);
		// decrement (prefix)
		Function_variable_iterator& operator--();
		// decrement (postfix)
		Function_variable_iterator operator--(int);
		// equality
		bool operator==(const Function_variable_iterator&) const;
		// inequality
		bool operator!=(const Function_variable_iterator&) const;
		// dereference
		Function_variable_handle operator*() const;
		// don't have a operator-> because its not needed and it would return a
		//   Function_variable_handle*
	private:
		Function_variable_iterator_representation *representation;
};

class Function_variable
//******************************************************************************
// LAST MODIFIED : 23 January 2005
//
// DESCRIPTION :
// A specification for an input/independent and/or output/dependent variable of
// a Function.
//==============================================================================
{
	template<class Value_type_1,class Value_type_2>
		friend bool equivalent(boost::intrusive_ptr<Value_type_1> const &,
		boost::intrusive_ptr<Value_type_2> const &);
	public:
		virtual Function_variable_handle clone() const=0;
		// if the variable is for a single function, the function is returned,
		//   otherwise a zero handle is returned
		virtual Function_handle function() const;
		// returns a specification for the type of variable's value
		virtual Function_variable_value_handle value();
#if defined (EVALUATE_RETURNS_VALUE)
		// evaluate creates a new Function which is the variable's value with the
		//   specified <input> replaced by the given <value>.  For a dependent
		//   variable, this will involve evaluating the variable's function
		virtual Function_handle evaluate();
		virtual Function_handle evaluate(Function_variable_handle input,
			Function_handle value);
#else // defined (EVALUATE_RETURNS_VALUE)
		// for a dependent variable, the variable's function will be evaluated.  For
		//   an independent variable, nothing will happen
		virtual bool evaluate();
#endif // defined (EVALUATE_RETURNS_VALUE)
#if defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// evaluate_derivative creates a new Function which is the value of the
		//   variable differentiated with respect to the <independent_variables>
		//   and the specified <input> replaced with given the <value>
		virtual Function_handle evaluate_derivative(
			std::list<Function_variable_handle>& independent_variables);
		virtual Function_handle evaluate_derivative(
			std::list<Function_variable_handle>& independent_variables,
			Function_variable_handle input,Function_handle value);
#else // defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// derivative creates a new Function which calculates the value of this
		//   variable differentiated with respect to the <independent_variables>
		virtual Function_handle derivative(
			const std::list<Function_variable_handle>& independent_variables);
#endif // defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// set_value changes the variable to have the <value> in the same order as
		//   evaluate.  Returns true if the variable is changed and false otherwise
		virtual bool set_value(Function_handle value);
		// rset_value changes the variable to have the <value> in the opposite order
		//   to evaluate (back to front).  Returns true if the variable is changed
		//   and false otherwise
		virtual bool rset_value(Function_handle value);
		// get_value creates a new Function which is the variable's value.  The
		//   variable's function is not evaluated
		virtual Function_handle get_value() const;
		// returns a string the represents the variable
		virtual string_handle get_string_representation()=0;
		// for stepping through the atomic variables that make up the variable.
		//   Atomic variables are indivisible, that is, two atomic variables are
		//   either the same or disjoint.  This is needed for determining the
		//   overlap between variables.  Atomic variables are for a single function
		virtual Function_variable_iterator begin_atomic() const=0;
		virtual Function_variable_iterator end_atomic() const=0;
		virtual std::reverse_iterator<Function_variable_iterator>
			rbegin_atomic() const=0;
		virtual std::reverse_iterator<Function_variable_iterator>
			rend_atomic() const=0;
		// returns the number of atomic variables that it makes sense to
		//   differentiate (output/dependent) or differentiate with respect to
		//   (input/independent)
		virtual Function_size_type number_differentiable();
		// the norm of the variable.  A negative result means that the norm is not
		//   defined
		virtual Scalar norm() const;
		// a zero handle indicates an error.  -= and += work in place.  - and +
		//   create new Functions and return their output variables
		virtual Function_variable_handle operator-(const Function_variable&) const;
		virtual Function_variable_handle operator-=(const Function_variable&);
		virtual Function_variable_handle operator+(const Function_variable&) const;
		virtual Function_variable_handle operator+=(const Function_variable&);
	public:
		// for caching function evaluations:
		// adds <dependent_function> to the list of functions that have to be
		//   re-evaluated if this variable's function(s) has/have to be re-evaluated
#if defined (CIRCULAR_SMART_POINTERS)
		virtual void add_dependent_function(
			const Function_handle dependent_function);
#else // defined (CIRCULAR_SMART_POINTERS)
		virtual void add_dependent_function(
			Function *dependent_function);
#endif // defined (CIRCULAR_SMART_POINTERS)
		// removes <dependent_function> to the list of functions that have to be
		//   re-evaluated if this variable's function(s) has/have to be re-evaluated
#if defined (CIRCULAR_SMART_POINTERS)
		virtual void remove_dependent_function(
			const Function_handle dependent_function);
#else // defined (CIRCULAR_SMART_POINTERS)
		virtual void remove_dependent_function(
			Function *dependent_function);
#endif // defined (CIRCULAR_SMART_POINTERS)
	private:
		virtual bool equality_atomic(const Function_variable_handle&) const=0;
		// equality operator.  To be used in equivalent
		virtual bool operator==(const Function_variable&) const;
	protected:
		// constructors.  Protected so that can't create "plain" Function_variables
		Function_variable(const Function_handle& function);
		// copy constructor
		Function_variable(const Function_variable&);
		// destructor.  Virtual for proper destruction of derived classes
		virtual ~Function_variable();
	private:
		// copy operations are private and undefined to prevent copying
		void operator=(const Function_variable&);
	protected:
		Function_handle function_private;
		Function_variable_value_handle value_private;
	private:
		mutable int reference_count;
		friend void intrusive_ptr_add_ref(Function_variable *);
		friend void intrusive_ptr_release(Function_variable *);
};

#endif /* !defined (__FUNCTION_VARIABLE_HPP__) */
<commit_msg>Changed back to USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE<commit_after>//******************************************************************************
// FILE : function_variable.hpp
//
// LAST MODIFIED : 23 January 2005
//
// DESCRIPTION :
// An abstract class for specifying input/independent and output/dependent
// variables of a function.
//
// Function_variables can be evaluated, differentiated or set to another value.
//==============================================================================
#if !defined (__FUNCTION_VARIABLE_HPP__)
#define __FUNCTION_VARIABLE_HPP__

#include <iterator>
#include <list>

#include "computed_variable/function_base.hpp"
#include "computed_variable/function_variable_value.hpp"

#define USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE

class Function_variable_iterator_representation
//******************************************************************************
// LAST MODIFIED : 2 March 2004
//
// DESCRIPTION :
//
// NOTES:
// To get iterators for a sub-class of Function_variable, derive a represenation
// class from this one.
//==============================================================================
{
	friend class Function_variable_iterator;
	public:
		// a "virtual" constructor
		virtual Function_variable_iterator_representation *clone()=0;
	protected:
		// destructor.  Virtual for proper destruction of derived classes
		virtual ~Function_variable_iterator_representation();
	private:
		// increment.  Do not want to return an object derived from
		//   Function_variable_iterator_representation.  Used by
		//   Function_variable_iterator::operator++() and ++(int)
		virtual void increment()=0;
		// decrement.  Do not want to return an object derived from
		//   Function_variable_iterator_representation.  Needs to be able to step
		//   from one past the last to the last.  Used by
		//   Function_variable_iterator::operator--() and --(int)
		virtual void decrement()=0;
		// equality.  Used by Function_variable_iterator::operator==() and !=()
		virtual bool equality(const Function_variable_iterator_representation*)=0;
		// dereference.  Used by Function_variable_iterator::operator*()
		virtual Function_variable_handle dereference() const=0;
	protected:
		// constructor.  Protected so that can't create "plain"
		//   Function_variable_iterator_representations
		Function_variable_iterator_representation();
	private:
		// copy operations are private and undefined to prevent copying
		Function_variable_iterator_representation(
			const Function_variable_iterator_representation&);
		Function_variable_iterator_representation& operator=(
			const Function_variable_iterator_representation&);
};

class Function_variable_iterator:
	public std::iterator<std::bidirectional_iterator_tag,Function_variable_handle,
	ptrdiff_t,Function_variable_handle*,Function_variable_handle>
//******************************************************************************
// LAST MODIFIED : 2 March 2004
//
// DESCRIPTION :
//
// NOTES:
// Do not derive from this class.  Derive from
// Function_variable_iterator_representation.
//
// The reference is Function_variable_handle rather the
// Function_variable_handle& (the default for std::iterator<>) because using
// smart pointers and because the objects in the pool being iterated are created
// by the iterator as required.
//==============================================================================
{
	public:
		// constructors
		Function_variable_iterator();
		Function_variable_iterator(Function_variable_iterator_representation *);
		// copy constructor
		Function_variable_iterator(const Function_variable_iterator&);
		// assignment
		Function_variable_iterator& operator=(const Function_variable_iterator&);
		// destructor
		~Function_variable_iterator();
		// increment (prefix)
		Function_variable_iterator& operator++();
		// increment (postfix)
		Function_variable_iterator operator++(int);
		// decrement (prefix)
		Function_variable_iterator& operator--();
		// decrement (postfix)
		Function_variable_iterator operator--(int);
		// equality
		bool operator==(const Function_variable_iterator&) const;
		// inequality
		bool operator!=(const Function_variable_iterator&) const;
		// dereference
		Function_variable_handle operator*() const;
		// don't have a operator-> because its not needed and it would return a
		//   Function_variable_handle*
	private:
		Function_variable_iterator_representation *representation;
};

class Function_variable
//******************************************************************************
// LAST MODIFIED : 23 January 2005
//
// DESCRIPTION :
// A specification for an input/independent and/or output/dependent variable of
// a Function.
//==============================================================================
{
	template<class Value_type_1,class Value_type_2>
		friend bool equivalent(boost::intrusive_ptr<Value_type_1> const &,
		boost::intrusive_ptr<Value_type_2> const &);
	public:
		virtual Function_variable_handle clone() const=0;
		// if the variable is for a single function, the function is returned,
		//   otherwise a zero handle is returned
		virtual Function_handle function() const;
		// returns a specification for the type of variable's value
		virtual Function_variable_value_handle value();
#if defined (EVALUATE_RETURNS_VALUE)
		// evaluate creates a new Function which is the variable's value with the
		//   specified <input> replaced by the given <value>.  For a dependent
		//   variable, this will involve evaluating the variable's function
		virtual Function_handle evaluate();
		virtual Function_handle evaluate(Function_variable_handle input,
			Function_handle value);
#else // defined (EVALUATE_RETURNS_VALUE)
		// for a dependent variable, the variable's function will be evaluated.  For
		//   an independent variable, nothing will happen
		virtual bool evaluate();
#endif // defined (EVALUATE_RETURNS_VALUE)
#if defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// evaluate_derivative creates a new Function which is the value of the
		//   variable differentiated with respect to the <independent_variables>
		//   and the specified <input> replaced with given the <value>
		virtual Function_handle evaluate_derivative(
			std::list<Function_variable_handle>& independent_variables);
		virtual Function_handle evaluate_derivative(
			std::list<Function_variable_handle>& independent_variables,
			Function_variable_handle input,Function_handle value);
#else // defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// derivative creates a new Function which calculates the value of this
		//   variable differentiated with respect to the <independent_variables>
		virtual Function_handle derivative(
			const std::list<Function_variable_handle>& independent_variables);
#endif // defined (USE_FUNCTION_VARIABLE__EVALUATE_DERIVATIVE)
		// set_value changes the variable to have the <value> in the same order as
		//   evaluate.  Returns true if the variable is changed and false otherwise
		virtual bool set_value(Function_handle value);
		// rset_value changes the variable to have the <value> in the opposite order
		//   to evaluate (back to front).  Returns true if the variable is changed
		//   and false otherwise
		virtual bool rset_value(Function_handle value);
		// get_value creates a new Function which is the variable's value.  The
		//   variable's function is not evaluated
		virtual Function_handle get_value() const;
		// returns a string the represents the variable
		virtual string_handle get_string_representation()=0;
		// for stepping through the atomic variables that make up the variable.
		//   Atomic variables are indivisible, that is, two atomic variables are
		//   either the same or disjoint.  This is needed for determining the
		//   overlap between variables.  Atomic variables are for a single function
		virtual Function_variable_iterator begin_atomic() const=0;
		virtual Function_variable_iterator end_atomic() const=0;
		virtual std::reverse_iterator<Function_variable_iterator>
			rbegin_atomic() const=0;
		virtual std::reverse_iterator<Function_variable_iterator>
			rend_atomic() const=0;
		// returns the number of atomic variables that it makes sense to
		//   differentiate (output/dependent) or differentiate with respect to
		//   (input/independent)
		virtual Function_size_type number_differentiable();
		// the norm of the variable.  A negative result means that the norm is not
		//   defined
		virtual Scalar norm() const;
		// a zero handle indicates an error.  -= and += work in place.  - and +
		//   create new Functions and return their output variables
		virtual Function_variable_handle operator-(const Function_variable&) const;
		virtual Function_variable_handle operator-=(const Function_variable&);
		virtual Function_variable_handle operator+(const Function_variable&) const;
		virtual Function_variable_handle operator+=(const Function_variable&);
	public:
		// for caching function evaluations:
		// adds <dependent_function> to the list of functions that have to be
		//   re-evaluated if this variable's function(s) has/have to be re-evaluated
#if defined (CIRCULAR_SMART_POINTERS)
		virtual void add_dependent_function(
			const Function_handle dependent_function);
#else // defined (CIRCULAR_SMART_POINTERS)
		virtual void add_dependent_function(
			Function *dependent_function);
#endif // defined (CIRCULAR_SMART_POINTERS)
		// removes <dependent_function> to the list of functions that have to be
		//   re-evaluated if this variable's function(s) has/have to be re-evaluated
#if defined (CIRCULAR_SMART_POINTERS)
		virtual void remove_dependent_function(
			const Function_handle dependent_function);
#else // defined (CIRCULAR_SMART_POINTERS)
		virtual void remove_dependent_function(
			Function *dependent_function);
#endif // defined (CIRCULAR_SMART_POINTERS)
	private:
		virtual bool equality_atomic(const Function_variable_handle&) const=0;
		// equality operator.  To be used in equivalent
		virtual bool operator==(const Function_variable&) const;
	protected:
		// constructors.  Protected so that can't create "plain" Function_variables
		Function_variable(const Function_handle& function);
		// copy constructor
		Function_variable(const Function_variable&);
		// destructor.  Virtual for proper destruction of derived classes
		virtual ~Function_variable();
	private:
		// copy operations are private and undefined to prevent copying
		void operator=(const Function_variable&);
	protected:
		Function_handle function_private;
		Function_variable_value_handle value_private;
	private:
		mutable int reference_count;
		friend void intrusive_ptr_add_ref(Function_variable *);
		friend void intrusive_ptr_release(Function_variable *);
};

#endif /* !defined (__FUNCTION_VARIABLE_HPP__) */
<|endoftext|>