<commit_before>#include "builtins/decl.hpp"

using std::string;
using std::shared_ptr;
using std::make_shared;
using std::vector;
using std::map;
using std::set;
using std::make_pair;
using std::move;
using backend::utility::make_vector;
using backend::utility::make_set;
using backend::utility::make_map;

namespace backend {

namespace builtins {

typedef std::tuple<const char*, fn_info> named_info;

namespace detail {

shared_ptr<const monotype_t> t_a =
    make_shared<const monotype_t>("a");

shared_ptr<const type_t> bin_op_t =
    make_shared<const polytype_t>(
        make_vector<shared_ptr<const monotype_t> >(t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)(t_a)),
            t_a));

shared_ptr<const type_t> bin_cmp_t =
    make_shared<const polytype_t>(
        make_vector<shared_ptr<const monotype_t> >(t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)(t_a)),
            bool_mt));

shared_ptr<const type_t> un_op_t =
     make_shared<const polytype_t>(
         make_vector<shared_ptr<const monotype_t> >(
             t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)),
            t_a));

shared_ptr<const phase_t> bin_phase_t =
    make_shared<const phase_t>(
        make_vector<completion>(completion::none)(completion::none),
        completion::invariant);

shared_ptr<const phase_t> un_phase_t =
    make_shared<const phase_t>(
        make_vector<completion>(
            completion::none),
        completion::invariant);

fn_info bin_op_info(bin_op_t, bin_phase_t);
fn_info bin_cmp_info(bin_cmp_t, bin_phase_t);
fn_info un_op_info(un_op_t, un_phase_t);
fn_info nullary_info(void_mt,
                     make_shared<const phase_t>(
                         make_vector<completion>(),
                         completion::invariant));

vector<named_info> binary_scalar_operators =
    make_vector<named_info>
    (named_info("op_add",    bin_op_info))
    (named_info("op_sub",    bin_op_info))
    (named_info("op_mul",    bin_op_info))
    (named_info("op_div",    bin_op_info))
    (named_info("op_mod",    bin_op_info))
    (named_info("op_lshift", bin_op_info))
    (named_info("op_rshift", bin_op_info))
    (named_info("op_or",     bin_op_info))
    (named_info("op_xor",    bin_op_info))
    (named_info("op_and",    bin_op_info))
    (named_info("cmp_eq",    bin_cmp_info))
    (named_info("cmp_ne",    bin_cmp_info))
    (named_info("cmp_lt",    bin_cmp_info))
    (named_info("cmp_le",    bin_cmp_info))
    (named_info("cmp_gt",    bin_cmp_info))
    (named_info("cmp_ge",    bin_cmp_info));

vector<named_info> unary_scalar_operators =
    make_vector<named_info>
    (named_info("op_invert", un_op_info))
    (named_info("op_pos",    un_op_info))
    (named_info("op_neg",    un_op_info))
    (named_info("op_not",    un_op_info));

vector<named_info> cpp_support_fns =
    make_vector<named_info>
    (named_info("wrap_cuarray", nullary_info))
    (named_info("make_scalar", nullary_info))
    (named_info("unpack_scalar", nullary_info));

}

void load_scalars(
    std::map<ident, fn_info>& fns,
    const vector<named_info>& names) {
    for(auto i = names.begin();
        i != names.end();
        i++) {
        fns.insert(
            make_pair(
                make_pair(
                    string(std::get<0>(*i)),
                    iteration_structure::scalar),
                std::get<1>(*i)));
    }
}

}

shared_ptr<library> get_builtins() {
    map<ident, fn_info> fns;
    builtins::load_scalars(fns, builtins::detail::unary_scalar_operators);
    builtins::load_scalars(fns, builtins::detail::binary_scalar_operators);
    builtins::load_scalars(fns, builtins::detail::cpp_support_fns);
    string path(detail::get_path(PRELUDE_PATH));
    set<string> include_paths;
    if (path.length() > 0) {
        include_paths.insert(path);
    }
    string include(PRELUDE_FILE);
    shared_ptr<library> l(new library(move(fns),
                                      make_map<string, string>(),
                                      make_set<string>(include),
                                      move(include_paths)));
    return l;
}

}
<commit_msg>Tuples beginning to work.<commit_after>#include "builtins/decl.hpp"

using std::string;
using std::shared_ptr;
using std::make_shared;
using std::vector;
using std::map;
using std::set;
using std::make_pair;
using std::move;
using backend::utility::make_vector;
using backend::utility::make_set;
using backend::utility::make_map;

namespace backend {

namespace builtins {

typedef std::tuple<const char*, fn_info> named_info;

namespace detail {

shared_ptr<const monotype_t> t_a =
    make_shared<const monotype_t>("a");

shared_ptr<const type_t> bin_op_t =
    make_shared<const polytype_t>(
        make_vector<shared_ptr<const monotype_t> >(t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)(t_a)),
            t_a));

shared_ptr<const type_t> bin_cmp_t =
    make_shared<const polytype_t>(
        make_vector<shared_ptr<const monotype_t> >(t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)(t_a)),
            bool_mt));

shared_ptr<const type_t> un_op_t =
     make_shared<const polytype_t>(
         make_vector<shared_ptr<const monotype_t> >(
             t_a),
        make_shared<const fn_t>(
            make_shared<const tuple_t>(
                make_vector<shared_ptr<const type_t> >(t_a)),
            t_a));

shared_ptr<const phase_t> bin_phase_t =
    make_shared<const phase_t>(
        make_vector<completion>(completion::none)(completion::none),
        completion::invariant);

shared_ptr<const phase_t> un_phase_t =
    make_shared<const phase_t>(
        make_vector<completion>(
            completion::none),
        completion::invariant);

fn_info bin_op_info(bin_op_t, bin_phase_t);
fn_info bin_cmp_info(bin_cmp_t, bin_phase_t);
fn_info un_op_info(un_op_t, un_phase_t);
fn_info nullary_info(void_mt,
                     make_shared<const phase_t>(
                         make_vector<completion>(),
                         completion::invariant));

vector<named_info> binary_scalar_operators =
    make_vector<named_info>
    (named_info("op_add",    bin_op_info))
    (named_info("op_sub",    bin_op_info))
    (named_info("op_mul",    bin_op_info))
    (named_info("op_div",    bin_op_info))
    (named_info("op_mod",    bin_op_info))
    (named_info("op_lshift", bin_op_info))
    (named_info("op_rshift", bin_op_info))
    (named_info("op_or",     bin_op_info))
    (named_info("op_xor",    bin_op_info))
    (named_info("op_and",    bin_op_info))
    (named_info("cmp_eq",    bin_cmp_info))
    (named_info("cmp_ne",    bin_cmp_info))
    (named_info("cmp_lt",    bin_cmp_info))
    (named_info("cmp_le",    bin_cmp_info))
    (named_info("cmp_gt",    bin_cmp_info))
    (named_info("cmp_ge",    bin_cmp_info));

vector<named_info> unary_scalar_operators =
    make_vector<named_info>
    (named_info("op_invert", un_op_info))
    (named_info("op_pos",    un_op_info))
    (named_info("op_neg",    un_op_info))
    (named_info("op_not",    un_op_info));

vector<named_info> cpp_support_fns =
    make_vector<named_info>
    (named_info("wrap_cuarray", nullary_info))
    (named_info("make_scalar", nullary_info))
    (named_info("unpack_scalar", nullary_info))
    //XXX Python infiltration!
    (named_info("make_python_tuple", nullary_info))
    (named_info("unpack_tuple", nullary_info));

}

void load_scalars(
    std::map<ident, fn_info>& fns,
    const vector<named_info>& names) {
    for(auto i = names.begin();
        i != names.end();
        i++) {
        fns.insert(
            make_pair(
                make_pair(
                    string(std::get<0>(*i)),
                    iteration_structure::scalar),
                std::get<1>(*i)));
    }
}

}

shared_ptr<library> get_builtins() {
    map<ident, fn_info> fns;
    builtins::load_scalars(fns, builtins::detail::unary_scalar_operators);
    builtins::load_scalars(fns, builtins::detail::binary_scalar_operators);
    builtins::load_scalars(fns, builtins::detail::cpp_support_fns);
    string path(detail::get_path(PRELUDE_PATH));
    set<string> include_paths;
    if (path.length() > 0) {
        include_paths.insert(path);
    }
    string include(PRELUDE_FILE);
    shared_ptr<library> l(new library(move(fns),
                                      make_map<string, string>(),
                                      make_set<string>(include),
                                      move(include_paths)));
    return l;
}

}
<|endoftext|>


<commit_before>#include "server.h"

#include <vector>
#include <iostream>

namespace mw {

	Server::Server(int port, ServerFilter* serverFilter) {
		status_ = NOT_ACTIVE;
		maxNbrOfRemoteClients_ = 4;

		address_.host = ENET_HOST_ANY;
		address_.port = port;

		// Garanties that the server always has the correct id.
		id_ = Network::SERVER_ID;

		// The id to be assigned to the next connected client.
		currentId_ = id_ + 1;
		serverFilter_ = serverFilter;
	}

	Server::~Server() {
		stop();
		if (thread_.joinable()) {
			thread_.join();
		}

		for (auto& pair : peers_) {
			enet_peer_reset(pair.first);
		}
		if (server_ != 0) {
			enet_host_destroy(server_);
		}
	}

	void Server::start() {
		std::lock_guard<std::mutex> lock(mutex_);
		if (status_ == NOT_ACTIVE) {
			status_ = ACTIVE;
			// Remove old packet.
			while (!sendPackets_.empty()) {
				sendPackets_.pop();
			}
			while (!receivePackets_.empty()) {
				receivePackets_.pop();
			}

			// Create a host.
			server_ = enet_host_create(&address_, 32, 2, 0, 0);
			if (server_ == NULL) {
				fprintf(stderr, "An error occured while trying to create an ENet server host\n");
				exit(EXIT_FAILURE);
			}

			thread_ = std::thread(&Server::update, this);
		}
	}

	void Server::stop() {
		std::lock_guard<std::mutex> lock(mutex_);
		if (status_ == ACTIVE) {
			status_ = DISCONNECTING;
			for (auto it = peers_.begin(); it != peers_.end(); ++it) {
				ENetPeer* peer = it->first;
				enet_peer_disconnect(peer, 0);
			}
		}
	}

	void Server::update() {
		mutex_.lock();
		Status tmp = status_;
		mutex_.unlock();
		while (tmp != NOT_ACTIVE) {
			mutex_.lock();
			ENetEvent eNetEvent;
			int eventStatus = 0;
			while (status_ != NOT_ACTIVE &&
				(eventStatus = enet_host_service(server_, &eNetEvent, 50)) > 0) {
				switch (eNetEvent.type) {
					case ENET_EVENT_TYPE_CONNECT:
						//printf("(Server) We got a new connection from %x\n",eNetEvent.peer->address.host);
						if (status_ != DISCONNECTING) {
							// Signal the client that a new client is connected!
							// Is the connection accepted?
							if (serverFilter_->sendThrough(Packet(), currentId_ + 1, currentId_ + 1, ServerFilter::NEW_CONNECTION)) {
								// Assign id to client and set the next id to an uniqe value.
								Pair pair(eNetEvent.peer, ++currentId_);
								peers_.push_back(pair);

								// Send info about the new client to everybody.
								sendConnectInfoToPeers(peers_);
								Packet iPacket;
							} else {
								enet_peer_disconnect(eNetEvent.peer, 0);
							}
						} else {
							// Stops new connections to be made.
							enet_peer_disconnect(eNetEvent.peer, 0);
						}
						break;
					case ENET_EVENT_TYPE_RECEIVE:
						if (status_ != NOT_ACTIVE) {
							InternalPacket iPacket = receive(eNetEvent);
							// No data to send? Or data through the filter is to be sent through?
							if (iPacket.data_.size() > 0 && serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::PACKET)) {
								// Sent to you specific?
								if (iPacket.toId_ == id_) {
									receivePackets_.push(iPacket);
								} else if (iPacket.toId_ != 0) { // Send to a specific client?
									sendPackets_.push(iPacket);
								} else { // Send to all!
									receivePackets_.push(iPacket);
									sendPackets_.push(iPacket);
								}
							}
						}
						enet_packet_destroy(eNetEvent.packet);
						break;
					case ENET_EVENT_TYPE_DISCONNECT:
					{
						printf("%s disconnected.\n", (char*) eNetEvent.peer->data);
						// Reset client's information
						auto it = peers_.begin();
						for (; it != peers_.end(); ++it) {
							if (it->first == eNetEvent.peer) {
								break;
							}
						}

						// Remove the connection if its old (i.e. it is in the vector
						// and not a turned down connection).
						if (it != peers_.end()) {
							InternalPacket iPacket(Packet(), it->second, PacketType::RELIABLE);

							// Signal the server that a client is disconnecting.
							serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::DISCONNECTED);

							// Remove peer from vector.
							std::swap(*it, peers_.back());
							peers_.pop_back();

							// Send the updated client list to all clients.
							sendConnectInfoToPeers(peers_);
						}

						// When all peers is disconnected, then clean up.
						if (status_ == DISCONNECTING && peers_.size() == 0) {
							eNetEvent.peer->data = NULL;
							status_ = NOT_ACTIVE;
						}

						eNetEvent.peer->data = NULL;
					}
						break;
					case ENET_EVENT_TYPE_NONE:
						break;
				}
			}

			// Send all packets in send buffer to all clients.
			while (status_ != NOT_ACTIVE && !sendPackets_.empty()) {
				InternalPacket& iPacket = sendPackets_.front();

				// Data to send? And data through the filter is allowed to be sent?
				if (iPacket.data_.size() > 0 && serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::PACKET)) {
					// Send the packet to the peer over channel id 0.
					// enet handles the cleen up of eNetPacket;
					for (auto it = peers_.begin(); it != peers_.end(); ++it) {
						int id = it->second;
						// Send to all?
						if (iPacket.toId_ == 0) {
							// The sender?
							if (iPacket.fromId_ == id) {
								// Skip to return data to the sender.
								continue;
							}
							ENetPacket* eNetPacket = createEnetPacket(iPacket.data_, iPacket.fromId_, iPacket.type_);
							ENetPeer* peer = it->first;
							enet_peer_send(peer, 0, eNetPacket);
						} else if (id == iPacket.toId_) { // Send to the specific client?
							ENetPacket* eNetPacket = createEnetPacket(iPacket.data_, iPacket.fromId_, iPacket.type_);
							ENetPeer* peer = it->first;
							enet_peer_send(peer, 0, eNetPacket);
							// Only send to one client.
							break;
						}
					}
				}

				sendPackets_.pop();
			}

			enet_host_flush(server_);

			// The server is not active? Or the disconnection is finish?
			if (status_ == NOT_ACTIVE || (status_ == DISCONNECTING && peers_.size() == 0)) {
				enet_host_destroy(server_);
				server_ = 0;
				status_ = NOT_ACTIVE;
			}

			mutex_.unlock();
			tmp = status_;
		}
	}

	Server::InternalPacket Server::receive(ENetEvent eNetEvent) {
		ENetPacket* packet = eNetEvent.packet;
		//char id = packet->data[1];
		//Find the id for the client which sent the package.
		auto it = peers_.begin();
		for (; it != peers_.end(); ++it) {
			if (it->first == eNetEvent.peer) {
				break;
			}
		}

		char id = it->second;
		// TODO!! Stop connection which violates the protocol.
		char type = packet->data[0];
		char toId = packet->data[1];
		switch (type) {
			case CONNECT_INFO:
				// ERROR. SERVER SHOULD ONLY SEND NOT RECEIVE CONNECT_INFO.
				// TODO!! Stop connection which violates the protocol.
				break;
			case PACKET:
				// [0]=type,[1]=id,[2...] = data
				return InternalPacket(mw::Packet((char*) packet->data + 2, packet->dataLength - 2), id, PacketType::RELIABLE, toId);
		}
		// TODO!! Stop connection which violates the protocol. ERROR.
		return InternalPacket(Packet(), 0, PacketType::RELIABLE);
	}

	// Sends connectInfo to new connected client. Client is assigned
	// the number id.
	// 0   char type = |CONNECT_INFO
	// 1   char id   = |id
	// 2   char id1  = |?
	//		...
	// N-1 char idN  = |?
	void Server::sendConnectInfoToPeers(const std::vector<Pair>& peers) const {
		char data[256];
		data[0] = CONNECT_INFO;
		for (const auto& pair : peers) {
			data[1] = pair.second;
			int size = peers.size();
			for (int i = 0; i < size; ++i) {
				data[i + 2] = peers[i].second;
			}

			ENetPacket* eNetPacket = enet_packet_create(data, size + 2, ENET_PACKET_FLAG_RELIABLE);
			enet_peer_send(pair.first, 0, eNetPacket);
		}
	}

} // Namespace mw.
<commit_msg>Bug fix! Calls to serverFilter does not lock the mutex.<commit_after>#include "server.h"

#include <vector>
#include <iostream>

namespace mw {

	Server::Server(int port, ServerFilter* serverFilter) {
		status_ = NOT_ACTIVE;
		maxNbrOfRemoteClients_ = 4;

		address_.host = ENET_HOST_ANY;
		address_.port = port;

		// Garanties that the server always has the correct id.
		id_ = Network::SERVER_ID;

		// The id to be assigned to the next connected client.
		currentId_ = id_ + 1;
		serverFilter_ = serverFilter;
	}

	Server::~Server() {
		stop();
		if (thread_.joinable()) {
			thread_.join();
		}

		for (auto& pair : peers_) {
			enet_peer_reset(pair.first);
		}
		if (server_ != 0) {
			enet_host_destroy(server_);
		}
	}

	void Server::start() {
		std::lock_guard<std::mutex> lock(mutex_);
		if (status_ == NOT_ACTIVE) {
			status_ = ACTIVE;
			// Remove old packet.
			while (!sendPackets_.empty()) {
				sendPackets_.pop();
			}
			while (!receivePackets_.empty()) {
				receivePackets_.pop();
			}

			// Create a host.
			server_ = enet_host_create(&address_, 32, 2, 0, 0);
			if (server_ == NULL) {
				fprintf(stderr, "An error occured while trying to create an ENet server host\n");
				exit(EXIT_FAILURE);
			}

			thread_ = std::thread(&Server::update, this);
		}
	}

	void Server::stop() {
		std::lock_guard<std::mutex> lock(mutex_);
		if (status_ == ACTIVE) {
			status_ = DISCONNECTING;
			for (auto it = peers_.begin(); it != peers_.end(); ++it) {
				ENetPeer* peer = it->first;
				enet_peer_disconnect(peer, 0);
			}
		}
	}

	void Server::update() {
		mutex_.lock();
		Status tmp = status_;
		mutex_.unlock();
		while (tmp != NOT_ACTIVE) {
			mutex_.lock();
			ENetEvent eNetEvent;
			int eventStatus = 0;
			while (status_ != NOT_ACTIVE &&
				(eventStatus = enet_host_service(server_, &eNetEvent, 50)) > 0) {
				switch (eNetEvent.type) {
					case ENET_EVENT_TYPE_CONNECT:
						//printf("(Server) We got a new connection from %x\n",eNetEvent.peer->address.host);
						if (status_ != DISCONNECTING) {
							// Signal the client that a new client is connected!
							// Is the connection accepted?
							mutex_.unlock();
							if (serverFilter_->sendThrough(Packet(), currentId_ + 1, currentId_ + 1, ServerFilter::NEW_CONNECTION)) {
								mutex_.lock();
								// Assign id to client and set the next id to an uniqe value.
								Pair pair(eNetEvent.peer, ++currentId_);
								peers_.push_back(pair);

								// Send info about the new client to everybody.
								sendConnectInfoToPeers(peers_);
								Packet iPacket;
							} else {
								mutex_.lock();
								enet_peer_disconnect(eNetEvent.peer, 0);
							}
						} else {
							// Stops new connections to be made.
							enet_peer_disconnect(eNetEvent.peer, 0);
						}
						break;
					case ENET_EVENT_TYPE_RECEIVE:
						if (status_ != NOT_ACTIVE) {
							InternalPacket iPacket = receive(eNetEvent);

							mutex_.unlock();
							// No data to send? Or data through the filter is to be sent through?
							if (iPacket.data_.size() > 0 && serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::PACKET)) {
								// Sent to you specific?
								mutex_.lock();
								if (iPacket.toId_ == id_) {
									receivePackets_.push(iPacket);
								} else if (iPacket.toId_ != 0) { // Send to a specific client?
									sendPackets_.push(iPacket);
								} else { // Send to all!
									receivePackets_.push(iPacket);
									sendPackets_.push(iPacket);
								}
							} else {
								mutex_.lock();
							}
						}
						enet_packet_destroy(eNetEvent.packet);
						break;
					case ENET_EVENT_TYPE_DISCONNECT:
					{
						printf("%s disconnected.\n", (char*) eNetEvent.peer->data);
						// Reset client's information
						auto it = peers_.begin();
						for (; it != peers_.end(); ++it) {
							if (it->first == eNetEvent.peer) {
								break;
							}
						}

						// Remove the connection if its old (i.e. it is in the vector
						// and not a turned down connection).
						if (it != peers_.end()) {
							InternalPacket iPacket(Packet(), it->second, PacketType::RELIABLE);
							mutex_.unlock();
							// Signal the server that a client is disconnecting.
							serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::DISCONNECTED);
							mutex_.lock();
							// Remove peer from vector.
							std::swap(*it, peers_.back());
							peers_.pop_back();

							// Send the updated client list to all clients.
							sendConnectInfoToPeers(peers_);
						}

						// When all peers is disconnected, then clean up.
						if (status_ == DISCONNECTING && peers_.size() == 0) {
							eNetEvent.peer->data = NULL;
							status_ = NOT_ACTIVE;
						}

						eNetEvent.peer->data = NULL;
					}
						break;
					case ENET_EVENT_TYPE_NONE:
						break;
				}
			}

			// Send all packets in send buffer to all clients.
			while (status_ != NOT_ACTIVE && !sendPackets_.empty()) {
				InternalPacket& iPacket = sendPackets_.front();

				mutex_.unlock();
				// Data to send? And data through the filter is allowed to be sent?
				if (iPacket.data_.size() > 0 && serverFilter_->sendThrough(iPacket.data_, iPacket.fromId_, iPacket.toId_, ServerFilter::PACKET)) {
					mutex_.lock();
					// Send the packet to the peer over channel id 0.
					// enet handles the cleen up of eNetPacket;
					for (auto it = peers_.begin(); it != peers_.end(); ++it) {
						int id = it->second;
						// Send to all?
						if (iPacket.toId_ == 0) {
							// The sender?
							if (iPacket.fromId_ == id) {
								// Skip to return data to the sender.
								continue;
							}
							ENetPacket* eNetPacket = createEnetPacket(iPacket.data_, iPacket.fromId_, iPacket.type_);
							ENetPeer* peer = it->first;
							enet_peer_send(peer, 0, eNetPacket);
						} else if (id == iPacket.toId_) { // Send to the specific client?
							ENetPacket* eNetPacket = createEnetPacket(iPacket.data_, iPacket.fromId_, iPacket.type_);
							ENetPeer* peer = it->first;
							enet_peer_send(peer, 0, eNetPacket);
							// Only send to one client.
							break;
						}
					}
				} else {
					mutex_.lock();
				}

				sendPackets_.pop();
			}

			enet_host_flush(server_);

			// The server is not active? Or the disconnection is finish?
			if (status_ == NOT_ACTIVE || (status_ == DISCONNECTING && peers_.size() == 0)) {
				enet_host_destroy(server_);
				server_ = 0;
				status_ = NOT_ACTIVE;
			}

			mutex_.unlock();
			tmp = status_;
		}
	}

	Server::InternalPacket Server::receive(ENetEvent eNetEvent) {
		ENetPacket* packet = eNetEvent.packet;
		//char id = packet->data[1];
		//Find the id for the client which sent the package.
		auto it = peers_.begin();
		for (; it != peers_.end(); ++it) {
			if (it->first == eNetEvent.peer) {
				break;
			}
		}

		char id = it->second;
		// TODO!! Stop connection which violates the protocol.
		char type = packet->data[0];
		char toId = packet->data[1];
		switch (type) {
			case CONNECT_INFO:
				// ERROR. SERVER SHOULD ONLY SEND NOT RECEIVE CONNECT_INFO.
				// TODO!! Stop connection which violates the protocol.
				break;
			case PACKET:
				// [0]=type,[1]=id,[2...] = data
				return InternalPacket(mw::Packet((char*) packet->data + 2, packet->dataLength - 2), id, PacketType::RELIABLE, toId);
		}
		// TODO!! Stop connection which violates the protocol. ERROR.
		return InternalPacket(Packet(), 0, PacketType::RELIABLE);
	}

	// Sends connectInfo to new connected client. Client is assigned
	// the number id.
	// 0   char type = |CONNECT_INFO
	// 1   char id   = |id
	// 2   char id1  = |?
	//		...
	// N-1 char idN  = |?
	void Server::sendConnectInfoToPeers(const std::vector<Pair>& peers) const {
		char data[256];
		data[0] = CONNECT_INFO;
		for (const auto& pair : peers) {
			data[1] = pair.second;
			int size = peers.size();
			for (int i = 0; i < size; ++i) {
				data[i + 2] = peers[i].second;
			}

			ENetPacket* eNetPacket = enet_packet_create(data, size + 2, ENET_PACKET_FLAG_RELIABLE);
			enet_peer_send(pair.first, 0, eNetPacket);
		}
	}

} // Namespace mw.
<|endoftext|>


<commit_before>#include <sstream>
#include <fstream>
#include <locale>

#include "xdCore.hpp"
#include "ConsoleCommand.hpp"

#pragma region ConsoleCommand Container
bool CC_Container::Execute(std::string cmd)
{
    std::string cmd_str, cmd_val;

    std::istringstream buffer(cmd);
    buffer >> cmd_str >> cmd_val;

    ConsoleCommand* command(GetCommand(cmd_str));
    if (command && command->isEnabled())
    {
        if (command->isLowerCaseArgs())
        {
            std::locale loc;
            for (auto&& elem : cmd_val)
                elem = std::tolower(elem, loc);
        }
        if (cmd_val.empty())
        {
            if (command->isEmptyArgsAllowed())
                command->Execute(cmd_val.c_str());
            else
                ConsoleMsg("{} {}", command->GetName(), command->Status());
        }
        else
            command->Execute(cmd_val.c_str());
    }
    else
    {
        ConsoleMsg("Unknown command: {}", cmd_str);
        return false;
    }
    return true;
}

void CC_Container::ExecuteConfig(std::string filename)
{
    filename.insert(0, "config_load ");
    Execute(filename);
}

ConsoleCommand* CC_Container::GetCommand(std::string cmd) const
{
    auto e = CommandsContainer.find(cmd);
    if (e != CommandsContainer.end())
    {
        return e->second;
    }
    else
    {
        return nullptr;
    }

}

bool CC_Container::GetBool(std::string cmd) const
{
    ConsoleCommand* command = GetCommand(cmd);
    CC_Bool* b = dynamic_cast<CC_Bool*>(command);
    if (b)
        return b->GetValue();
    return false;
}

void CC_Container::AddCommand(ConsoleCommand* cc)
{
    CommandsContainer[cc->GetName()] = cc;
}

void CC_Container::RemoveCommand(ConsoleCommand* cc)
{
    auto e = CommandsContainer.find(cc->GetName());
    if (e != CommandsContainer.end())
        CommandsContainer.erase(e);
}

void CC_Container::Destroy()
{
    CommandsContainer.clear();
}
#pragma endregion ConsoleCommand Container

#pragma region Basic ConsoleCommand
ConsoleCommand::ConsoleCommand(std::string _name) : Name(_name), Enabled(true), LowerCaseArgs(true), AllowEmptyArgs(false), AllowSaving(true)
{
    CommandsCache.reserve(LRUCount + 1);
    CommandsCache.erase(CommandsCache.begin(), CommandsCache.end());
}

ConsoleCommand::~ConsoleCommand()
{
    if (ConsoleCommands)
        ConsoleCommands->RemoveCommand(this);
}

std::string ConsoleCommand::GetName()
{
    return Name;
}

bool ConsoleCommand::isEnabled()
{
    return Enabled;
}

bool ConsoleCommand::isLowerCaseArgs()
{
    return LowerCaseArgs;
}

bool ConsoleCommand::isEmptyArgsAllowed()
{
    return AllowEmptyArgs;
}

bool ConsoleCommand::isSavingAllowed()
{
    return AllowSaving;
}

std::string ConsoleCommand::Status()
{
    return "no value";
}

std::string ConsoleCommand::Info()
{
    return "basic ConsoleCommand class";
}

std::string ConsoleCommand::Syntax()
{
    return "no arguments";
}

void ConsoleCommand::InvalidSyntax(std::string args)
{
    ConsoleMsg("Invalid syntax in call [{} {}]", Name, args);
    ConsoleMsg("Valid arguments: {}", Syntax());
}

std::string ConsoleCommand::Save()
{
    return GetName() + " " + Status();
}

void ConsoleCommand::AddCommandToCache(std::string&& cmd)
{
    if (cmd.size() == 0 || AllowEmptyArgs)
    {
        return;
    }
    bool isDublicate = std::find(CommandsCache.begin(), CommandsCache.end(), cmd) != CommandsCache.end();
    if (!isDublicate)
    {
        CommandsCache.push_back(cmd);
        if (CommandsCache.size() > LRUCount)
        {
            CommandsCache.erase(CommandsCache.begin());
        }
    }
}
#pragma endregion Basic ConsoleCommand

#pragma region ConsoleCommand Boolean
CC_Bool::CC_Bool(std::string _name, bool& _value) : super(_name), value(_value) {}

void CC_Bool::Execute(std::string args)
{
    bool v;
    if (args.compare("on") == 0 || args.compare("true") == 0 || args.compare("1") == 0)
    {
        v = true;
    }
    else if (args.compare("off") !=0 || args.compare("false") != 0 || args.compare("0") != 0)
    {
        v = false;
    }
    else
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Bool::Info()
{
    return "boolean value";
}

std::string CC_Bool::Syntax()
{
    return "on/off, true/false, 1/0";
}
std::string CC_Bool::Status()
{
    return value ? "on" : "off";
}

const bool CC_Bool::GetValue() const
{
    return value;
}

#pragma endregion ConsoleCommand Boolean

#pragma region ConsoleCommand Toggle
CC_Toggle::CC_Toggle(std::string _name, bool& _value) : super(_name), value(_value)
{
    AllowEmptyArgs = true;
    AllowSaving = false;
}

void CC_Toggle::Execute(std::string args)
{
    value = !value;
}

std::string CC_Toggle::Info()
{
    return "toggler";
}

std::string CC_Toggle::Status()
{
    return value ? "on" : "off";
}

#pragma endregion ConsoleCommand Toggle

#pragma region ConsoleCommand String
CC_String::CC_String(std::string _name, std::string _value, unsigned _size)
    : super(_name), value(_value), size(_size)
{}

void CC_String::Execute(std::string args)
{
    if (args.length() > size)
    {
        InvalidSyntax(args);
        return;
    }
    value = args;
}

std::string CC_String::Info()
{
    return "string value";
}

std::string CC_String::Syntax()
{
    return fmt::format("max size is {}", size);
}

std::string CC_String::Status()
{
    return value;
}

#pragma endregion ConsoleCommand String

#pragma region ConsoleCommand Value Template
template<class T>
CC_Value<T>::CC_Value(std::string _name, T& _value, T const _min, T const _max)
    : super(_name), value(_value), min(_min), max(_max) {}

template<class T>
std::string CC_Value<T>::Syntax()
{
    return fmt::format("range [{}, {}]", min, max);
}
#pragma endregion ConsoleCommand Value Template

#pragma region ConsoleCommand Integer
CC_Integer::CC_Integer(std::string _name, int& _value, int const _min, int const _max)
    : super(_name, _value, _min, _max) {}

void CC_Integer::Execute(std::string args)
{
    unsigned v;
    if (1 != sscanf_s(args.c_str(), "%d", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }

    value = v;
}

std::string CC_Integer::Info()
{
    return "integer value";
}

std::string CC_Integer::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Integer

#pragma region ConsoleCommand Float
CC_Float::CC_Float(std::string _name, float& _value, float const _min, float const _max)
    : super(_name, _value, _min, _max) {}

void CC_Float::Execute(std::string args)
{
    float v = min;
    if (1 != sscanf_s(args.c_str(), "%f", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Float::Info()
{
    return "float value";
}

std::string CC_Float::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Float

#pragma region ConsoleCommand Double
CC_Double::CC_Double(std::string _name, double& _value, double const _min, double const _max)
    : super(_name, _value, _min, _max) {}

void CC_Double::Execute(std::string args)
{
    float v = min;
    if (1 != sscanf_s(args.c_str(), "%f", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Double::Info()
{
    return "double value";
}

std::string CC_Double::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Double

#pragma region ConsoleCommand Function Call
CC_FunctionCall::CC_FunctionCall(std::string _name, void (*_func)(std::string), bool _AllowEmptyArgs) : super(_name)
{
    AllowEmptyArgs = _AllowEmptyArgs;
    AllowSaving = false;
    function = _func;
}

void CC_FunctionCall::Execute(std::string args)
{
    if (function)
        function(args);
}

std::string CC_FunctionCall::Info()
{
    return "function call";
}

#pragma endregion ConsoleCommand Function Call

void ConfigLoad(std::string args)
{
    ConsoleMsg("Loading config file {}...", args.empty() ? Console->ConfigFile.string() : args);
    std::ifstream config_file(args.empty() ? Console->ConfigFile : args);
    std::string line;

    if (config_file.is_open())
    {
        while (std::getline(config_file, line))
            ConsoleCommands->Execute(line);
        ConsoleMsg("Loaded config file {}", args.empty() ? Console->ConfigFile.string() : args);
    }
    else
        ConsoleMsg("Failed to open config file {}", args.empty() ? Console->ConfigFile.string() : args);

    config_file.close();
}

void ConfigSave(std::string args)
{
    ConsoleMsg("Saving config file {}...", args.empty() ? Console->ConfigFile.string() : args);
    std::ofstream f(args.empty() ? Console->ConfigFile : args);
    for (auto str : ConsoleCommands->CommandsContainer)
    {
        auto CommandToSave = str.second;
        if (CommandToSave->isSavingAllowed())
            f << CommandToSave->Save() << std::endl;
    }
    f.close();
    ConsoleMsg("Saved config file {}", args.empty() ? Console->ConfigFile.string() : args);
}

void Help(std::string args)
{
    ConsoleCommand* CommandToHelp;
    if (!args.empty())
    {
        CommandToHelp = ConsoleCommands->GetCommand(args);
        if (CommandToHelp)
            ConsoleMsg("{} : {}. Current value: {}. Syntax: {}", CommandToHelp->GetName(), CommandToHelp->Info(), CommandToHelp->Status(), CommandToHelp->Syntax())
        else
            Console->Log("Command not found.");
    }
    else
    {
        Console->Log("Available commands:");
        for (auto str : ConsoleCommands->CommandsContainer)
        {
            CommandToHelp = str.second;
            ConsoleMsg("{} : {}. Current value: {}. Syntax: {}", CommandToHelp->GetName(), CommandToHelp->Info(), CommandToHelp->Status(), CommandToHelp->Syntax());
        }
    }
}

bool r_fullscreen = false;

int int_test = 1;
float float_test = 1.0;
double double_test = 1.0;
bool toggle_test = false;
std::string string_test = "test";

void RegisterConsoleCommands()
{
    /*
        A bit of help:

        CC_FunctionCall  CMD3(CC_FunctionCall, command_name_in_this_file, "command_name_in_console", function_to_call, is_empty_args_allowed);

        CC_Bool          CMD2(CC_Bool,         command_name_in_this_file, "command_name_in_console", variable_to_change);

        CC_Toggle        CMD2(CC_Toggle,       command_name_in_this_file, "command_name_in_console", variable_to_change);

        CC_Integer       CMD4(CC_Integer,      command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_Float         CMD4(CC_Float,        command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_Double        CMD4(CC_Double,       command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_String        CMD3(CC_String,       command_name_in_this_file, "command_name_in_console", variable_to_change, max_string_size);
    */

    CMD3(CC_FunctionCall, HelpCC, "help", Help, true);

    CMD3(CC_FunctionCall, ConfigLoadCC, "config_load", ConfigLoad, true);
    CMD3(CC_FunctionCall, ConfigSaveCC, "config_save", ConfigSave, true);

    CMD2(CC_Bool, FullscreenCC, "r_fullscreen", r_fullscreen);

    CMD2(CC_Toggle, toggle_testCC, "toggle_test", toggle_test);
    CMD4(CC_Integer, int_testCC, "int_test", int_test, 1, 10);
    CMD4(CC_Float, float_testCC, "float_test", float_test, 1.0, 10.0);
    CMD4(CC_Double, double_testCC, "double_test", double_test, 1.0, 10.0);
    CMD3(CC_String, string_testCC, "string_test", string_test, 512);
}
<commit_msg>New "exit" console command<commit_after>#include <sstream>
#include <fstream>
#include <locale>

#include <GLFW/glfw3.h>

#include "xdCore.hpp"
#include "xdEngine.hpp"
#include "ConsoleCommand.hpp"

#pragma region ConsoleCommand Container
bool CC_Container::Execute(std::string cmd)
{
    std::string cmd_str, cmd_val;

    std::istringstream buffer(cmd);
    buffer >> cmd_str >> cmd_val;

    ConsoleCommand* command(GetCommand(cmd_str));
    if (command && command->isEnabled())
    {
        if (command->isLowerCaseArgs())
        {
            std::locale loc;
            for (auto&& elem : cmd_val)
                elem = std::tolower(elem, loc);
        }
        if (cmd_val.empty())
        {
            if (command->isEmptyArgsAllowed())
                command->Execute(cmd_val.c_str());
            else
                ConsoleMsg("{} {}", command->GetName(), command->Status());
        }
        else
            command->Execute(cmd_val.c_str());
    }
    else
    {
        ConsoleMsg("Unknown command: {}", cmd_str);
        return false;
    }
    return true;
}

void CC_Container::ExecuteConfig(std::string filename)
{
    filename.insert(0, "config_load ");
    Execute(filename);
}

ConsoleCommand* CC_Container::GetCommand(std::string cmd) const
{
    auto e = CommandsContainer.find(cmd);
    if (e != CommandsContainer.end())
    {
        return e->second;
    }
    else
    {
        return nullptr;
    }

}

bool CC_Container::GetBool(std::string cmd) const
{
    ConsoleCommand* command = GetCommand(cmd);
    CC_Bool* b = dynamic_cast<CC_Bool*>(command);
    if (b)
        return b->GetValue();
    return false;
}

void CC_Container::AddCommand(ConsoleCommand* cc)
{
    CommandsContainer[cc->GetName()] = cc;
}

void CC_Container::RemoveCommand(ConsoleCommand* cc)
{
    auto e = CommandsContainer.find(cc->GetName());
    if (e != CommandsContainer.end())
        CommandsContainer.erase(e);
}

void CC_Container::Destroy()
{
    CommandsContainer.clear();
}
#pragma endregion ConsoleCommand Container

#pragma region Basic ConsoleCommand
ConsoleCommand::ConsoleCommand(std::string _name) : Name(_name), Enabled(true), LowerCaseArgs(true), AllowEmptyArgs(false), AllowSaving(true)
{
    CommandsCache.reserve(LRUCount + 1);
    CommandsCache.erase(CommandsCache.begin(), CommandsCache.end());
}

ConsoleCommand::~ConsoleCommand()
{
    if (ConsoleCommands)
        ConsoleCommands->RemoveCommand(this);
}

std::string ConsoleCommand::GetName()
{
    return Name;
}

bool ConsoleCommand::isEnabled()
{
    return Enabled;
}

bool ConsoleCommand::isLowerCaseArgs()
{
    return LowerCaseArgs;
}

bool ConsoleCommand::isEmptyArgsAllowed()
{
    return AllowEmptyArgs;
}

bool ConsoleCommand::isSavingAllowed()
{
    return AllowSaving;
}

std::string ConsoleCommand::Status()
{
    return "no value";
}

std::string ConsoleCommand::Info()
{
    return "basic ConsoleCommand class";
}

std::string ConsoleCommand::Syntax()
{
    return "no arguments";
}

void ConsoleCommand::InvalidSyntax(std::string args)
{
    ConsoleMsg("Invalid syntax in call [{} {}]", Name, args);
    ConsoleMsg("Valid arguments: {}", Syntax());
}

std::string ConsoleCommand::Save()
{
    return GetName() + " " + Status();
}

void ConsoleCommand::AddCommandToCache(std::string&& cmd)
{
    if (cmd.size() == 0 || AllowEmptyArgs)
    {
        return;
    }
    bool isDublicate = std::find(CommandsCache.begin(), CommandsCache.end(), cmd) != CommandsCache.end();
    if (!isDublicate)
    {
        CommandsCache.push_back(cmd);
        if (CommandsCache.size() > LRUCount)
        {
            CommandsCache.erase(CommandsCache.begin());
        }
    }
}
#pragma endregion Basic ConsoleCommand

#pragma region ConsoleCommand Boolean
CC_Bool::CC_Bool(std::string _name, bool& _value) : super(_name), value(_value) {}

void CC_Bool::Execute(std::string args)
{
    bool v;
    if (args.compare("on") == 0 || args.compare("true") == 0 || args.compare("1") == 0)
    {
        v = true;
    }
    else if (args.compare("off") !=0 || args.compare("false") != 0 || args.compare("0") != 0)
    {
        v = false;
    }
    else
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Bool::Info()
{
    return "boolean value";
}

std::string CC_Bool::Syntax()
{
    return "on/off, true/false, 1/0";
}
std::string CC_Bool::Status()
{
    return value ? "on" : "off";
}

const bool CC_Bool::GetValue() const
{
    return value;
}

#pragma endregion ConsoleCommand Boolean

#pragma region ConsoleCommand Toggle
CC_Toggle::CC_Toggle(std::string _name, bool& _value) : super(_name), value(_value)
{
    AllowEmptyArgs = true;
    AllowSaving = false;
}

void CC_Toggle::Execute(std::string args)
{
    value = !value;
}

std::string CC_Toggle::Info()
{
    return "toggler";
}

std::string CC_Toggle::Status()
{
    return value ? "on" : "off";
}

#pragma endregion ConsoleCommand Toggle

#pragma region ConsoleCommand String
CC_String::CC_String(std::string _name, std::string _value, unsigned _size)
    : super(_name), value(_value), size(_size)
{}

void CC_String::Execute(std::string args)
{
    if (args.length() > size)
    {
        InvalidSyntax(args);
        return;
    }
    value = args;
}

std::string CC_String::Info()
{
    return "string value";
}

std::string CC_String::Syntax()
{
    return fmt::format("max size is {}", size);
}

std::string CC_String::Status()
{
    return value;
}

#pragma endregion ConsoleCommand String

#pragma region ConsoleCommand Value Template
template<class T>
CC_Value<T>::CC_Value(std::string _name, T& _value, T const _min, T const _max)
    : super(_name), value(_value), min(_min), max(_max) {}

template<class T>
std::string CC_Value<T>::Syntax()
{
    return fmt::format("range [{}, {}]", min, max);
}
#pragma endregion ConsoleCommand Value Template

#pragma region ConsoleCommand Integer
CC_Integer::CC_Integer(std::string _name, int& _value, int const _min, int const _max)
    : super(_name, _value, _min, _max) {}

void CC_Integer::Execute(std::string args)
{
    unsigned v;
    if (1 != sscanf_s(args.c_str(), "%d", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }

    value = v;
}

std::string CC_Integer::Info()
{
    return "integer value";
}

std::string CC_Integer::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Integer

#pragma region ConsoleCommand Float
CC_Float::CC_Float(std::string _name, float& _value, float const _min, float const _max)
    : super(_name, _value, _min, _max) {}

void CC_Float::Execute(std::string args)
{
    float v = min;
    if (1 != sscanf_s(args.c_str(), "%f", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Float::Info()
{
    return "float value";
}

std::string CC_Float::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Float

#pragma region ConsoleCommand Double
CC_Double::CC_Double(std::string _name, double& _value, double const _min, double const _max)
    : super(_name, _value, _min, _max) {}

void CC_Double::Execute(std::string args)
{
    float v = min;
    if (1 != sscanf_s(args.c_str(), "%f", &v) || v < min || v > max)
    {
        InvalidSyntax(args);
        return;
    }
    value = v;
}

std::string CC_Double::Info()
{
    return "double value";
}

std::string CC_Double::Status()
{
    return std::to_string(value);
}
#pragma endregion ConsoleCommand Double

#pragma region ConsoleCommand Function Call
CC_FunctionCall::CC_FunctionCall(std::string _name, void (*_func)(std::string), bool _AllowEmptyArgs) : super(_name)
{
    AllowEmptyArgs = _AllowEmptyArgs;
    AllowSaving = false;
    function = _func;
}

void CC_FunctionCall::Execute(std::string args)
{
    if (function)
        function(args);
}

std::string CC_FunctionCall::Info()
{
    return "function call";
}

#pragma endregion ConsoleCommand Function Call

void ConfigLoad(std::string args)
{
    ConsoleMsg("Loading config file {}...", args.empty() ? Console->ConfigFile.string() : args);
    std::ifstream config_file(args.empty() ? Console->ConfigFile : args);
    std::string line;

    if (config_file.is_open())
    {
        while (std::getline(config_file, line))
            ConsoleCommands->Execute(line);
        ConsoleMsg("Loaded config file {}", args.empty() ? Console->ConfigFile.string() : args);
    }
    else
        ConsoleMsg("Failed to open config file {}", args.empty() ? Console->ConfigFile.string() : args);

    config_file.close();
}

void ConfigSave(std::string args)
{
    ConsoleMsg("Saving config file {}...", args.empty() ? Console->ConfigFile.string() : args);
    std::ofstream f(args.empty() ? Console->ConfigFile : args);
    for (auto str : ConsoleCommands->CommandsContainer)
    {
        auto CommandToSave = str.second;
        if (CommandToSave->isSavingAllowed())
            f << CommandToSave->Save() << std::endl;
    }
    f.close();
    ConsoleMsg("Saved config file {}", args.empty() ? Console->ConfigFile.string() : args);
}

void CC_Help(std::string args)
{
    ConsoleCommand* CommandToHelp;
    if (!args.empty())
    {
        CommandToHelp = ConsoleCommands->GetCommand(args);
        if (CommandToHelp)
            ConsoleMsg("{} : {}. Current value: {}. Syntax: {}", CommandToHelp->GetName(), CommandToHelp->Info(), CommandToHelp->Status(), CommandToHelp->Syntax())
        else
            Console->Log("Command not found.");
    }
    else
    {
        Console->Log("Available commands:");
        for (auto str : ConsoleCommands->CommandsContainer)
        {
            CommandToHelp = str.second;
            ConsoleMsg("{} : {}. Current value: {}. Syntax: {}", CommandToHelp->GetName(), CommandToHelp->Info(), CommandToHelp->Status(), CommandToHelp->Syntax());
        }
    }
}

void CC_Exit(std::string args)
{
    glfwSetWindowShouldClose(Engine.window, GLFW_TRUE);
}

bool r_fullscreen = false;

int int_test = 1;
float float_test = 1.0;
double double_test = 1.0;
bool toggle_test = false;
std::string string_test = "test";

void RegisterConsoleCommands()
{
    /*
        A bit of help:

        CC_FunctionCall  CMD3(CC_FunctionCall, command_name_in_this_file, "command_name_in_console", function_to_call, is_empty_args_allowed);

        CC_Bool          CMD2(CC_Bool,         command_name_in_this_file, "command_name_in_console", variable_to_change);

        CC_Toggle        CMD2(CC_Toggle,       command_name_in_this_file, "command_name_in_console", variable_to_change);

        CC_Integer       CMD4(CC_Integer,      command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_Float         CMD4(CC_Float,        command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_Double        CMD4(CC_Double,       command_name_in_this_file, "command_name_in_console", variable_to_change, minimum_value, maximum_value);

        CC_String        CMD3(CC_String,       command_name_in_this_file, "command_name_in_console", variable_to_change, max_string_size);
    */
    CMD3(CC_FunctionCall, ExitCC, "exit", CC_Exit, true);
    CMD3(CC_FunctionCall, QuitCC, "quit", CC_Exit, true);

    CMD3(CC_FunctionCall, HelpCC, "help", CC_Help, true);

    CMD3(CC_FunctionCall, ConfigLoadCC, "config_load", ConfigLoad, true);
    CMD3(CC_FunctionCall, ConfigSaveCC, "config_save", ConfigSave, true);

    CMD2(CC_Bool, FullscreenCC, "r_fullscreen", r_fullscreen);

    CMD2(CC_Toggle, toggle_testCC, "toggle_test", toggle_test);
    CMD4(CC_Integer, int_testCC, "int_test", int_test, 1, 10);
    CMD4(CC_Float, float_testCC, "float_test", float_test, 1.0, 10.0);
    CMD4(CC_Double, double_testCC, "double_test", double_test, 1.0, 10.0);
    CMD3(CC_String, string_testCC, "string_test", string_test, 512);
}
<|endoftext|>


<commit_before>#include "python.hpp"

#include <boost/assert.hpp>
#include <boost/regex.hpp>

namespace bacs{namespace system{namespace builders
{
    const bool python::factory_reg_hook = builder::register_new("python",
        [](const std::vector<std::string> &arguments)
        {
            builder_ptr tmp(new python(arguments));
            return tmp;
        });

    static const boost::regex positional("[^=]+"), key_value("([^=]+)=(.*)");

    python::python(const std::vector<std::string> &arguments)
    {
        for (const std::string &arg: arguments)
        {
            boost::smatch match;
            /*if (boost::regex_match(arg, match, positional))
            {
                BOOST_ASSERT(match.size() == 1);
            }
            else */if (boost::regex_match(arg, match, key_value))
            {
                BOOST_ASSERT(match.size() == 3);
                const std::string key = match[1].str(), value = match[2].str();
                if (key == "lang")
                {
                    m_lang = value;
                }
                else
                {
                    BOOST_THROW_EXCEPTION(
                        invalid_argument_error() <<
                        invalid_argument_error::argument(arg));
                }
            }
            else
            {
                BOOST_THROW_EXCEPTION(
                    invalid_argument_error() <<
                    invalid_argument_error::argument(arg));
            }
        }
    }

    ProcessPointer python::create_process(
        const ProcessGroupPointer &process_group,
        const name_type &name)
    {
        const ProcessPointer process =
            process_group->createProcess("python" + m_lang);
        process->setArguments(process->executable(), "-c", R"EOF(
import sys
import py_compile

if __name__=='__main__':
    src = sys.argv[1]
    try:
        py_compile.compile(src, doraise=True)
    except py_compile.PyCompileError as e:
        print(e.msg, file=sys.stderr)
        sys.exit(1)

        )EOF", name.source);
        return process;
    }

    executable_ptr python::create_executable(
        const ContainerPointer &container,
        bunsan::tempfile &&tmpdir,
        const name_type &name)
    {
        BOOST_ASSERT(m_flags.empty());
        const executable_ptr tmp(new interpretable_executable(
            container, std::move(tmpdir), name, "python" + m_lang));
        return tmp;
    }
}}}
<commit_msg>builders::python::create_process() bug fix.<commit_after>#include "python.hpp"

#include <boost/assert.hpp>
#include <boost/regex.hpp>

namespace bacs{namespace system{namespace builders
{
    const bool python::factory_reg_hook = builder::register_new("python",
        [](const std::vector<std::string> &arguments)
        {
            builder_ptr tmp(new python(arguments));
            return tmp;
        });

    static const boost::regex positional("[^=]+"), key_value("([^=]+)=(.*)");

    python::python(const std::vector<std::string> &arguments)
    {
        for (const std::string &arg: arguments)
        {
            boost::smatch match;
            /*if (boost::regex_match(arg, match, positional))
            {
                BOOST_ASSERT(match.size() == 1);
            }
            else */if (boost::regex_match(arg, match, key_value))
            {
                BOOST_ASSERT(match.size() == 3);
                const std::string key = match[1].str(), value = match[2].str();
                if (key == "lang")
                {
                    m_lang = value;
                }
                else
                {
                    BOOST_THROW_EXCEPTION(
                        invalid_argument_error() <<
                        invalid_argument_error::argument(arg));
                }
            }
            else
            {
                BOOST_THROW_EXCEPTION(
                    invalid_argument_error() <<
                    invalid_argument_error::argument(arg));
            }
        }
    }

    ProcessPointer python::create_process(
        const ProcessGroupPointer &process_group,
        const name_type &name)
    {
        const ProcessPointer process =
            process_group->createProcess("python" + m_lang);
        process->setArguments(process->executable(), "-c", R"EOF(
import sys
import py_compile

if __name__=='__main__':
    src = sys.argv[1]
    try:
        py_compile.compile(src, doraise=True)
    except py_compile.PyCompileError as e:
        sys.stderr.write(e.msg)
        sys.exit(1)

        )EOF", name.source);
        return process;
    }

    executable_ptr python::create_executable(
        const ContainerPointer &container,
        bunsan::tempfile &&tmpdir,
        const name_type &name)
    {
        BOOST_ASSERT(m_flags.empty());
        const executable_ptr tmp(new interpretable_executable(
            container, std::move(tmpdir), name, "python" + m_lang));
        return tmp;
    }
}}}
<|endoftext|>


<commit_before>//****************************************************************************//
// submesh.cpp                                                                //
// Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
//****************************************************************************//
// This library is free software; you can redistribute it and/or modify it    //
// under the terms of the GNU Lesser General Public License as published by   //
// the Free Software Foundation; either version 2.1 of the License, or (at    //
// your option) any later version.                                            //
//****************************************************************************//

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "cal3d/submesh.h"
#include "cal3d/error.h"
#include "cal3d/coresubmesh.h"

CalSubmesh::CalSubmesh(CalCoreSubmesh* coreSubmesh)
{
  assert(coreSubmesh);

  m_pCoreSubmesh = coreSubmesh;

  // reserve memory for the face vector
  m_vectorFace.reserve(m_pCoreSubmesh->getFaceCount());
  m_vectorFace.resize(m_pCoreSubmesh->getFaceCount());

  // set the initial lod level
  setLodLevel(1.0f);

  // set the initial material id
  m_coreMaterialId = -1;

  //Setting the morph target weights
  m_vectorMorphTargetWeight.reserve(m_pCoreSubmesh->getCoreSubMorphTargetCount());
  m_vectorMorphTargetWeight.resize(m_pCoreSubmesh->getCoreSubMorphTargetCount());
  int morphTargetId;
  for(morphTargetId = 0; morphTargetId<m_pCoreSubmesh->getCoreSubMorphTargetCount();++morphTargetId)
  {
    m_vectorMorphTargetWeight[morphTargetId] = 0.0f;
  }

  // check if the submesh instance must handle the vertex and normal data internally
  if(m_pCoreSubmesh->getSpringCount() > 0)
  {
    m_vectorVertex.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorVertex.resize(m_pCoreSubmesh->getVertexCount());
    m_vectorNormal.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorNormal.resize(m_pCoreSubmesh->getVertexCount());

    m_vectorvectorTangentSpace.reserve(m_pCoreSubmesh->getVectorVectorTangentSpace().size());
    m_vectorvectorTangentSpace.resize(m_pCoreSubmesh->getVectorVectorTangentSpace().size());

    m_vectorPhysicalProperty.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorPhysicalProperty.resize(m_pCoreSubmesh->getVertexCount());

    // get the vertex vector of the core submesh
    std::vector<CalCoreSubmesh::Vertex>& vectorVertex = m_pCoreSubmesh->getVectorVertex();

    // copy the data from the core submesh as default values
    int vertexId;
    for(vertexId = 0; vertexId < m_pCoreSubmesh->getVertexCount(); ++vertexId)
    {
      // copy the vertex data
      m_vectorVertex[vertexId] = vectorVertex[vertexId].position;
      m_vectorPhysicalProperty[vertexId].position = vectorVertex[vertexId].position;
      m_vectorPhysicalProperty[vertexId].positionOld = vectorVertex[vertexId].position;

      // copy the normal data
      m_vectorNormal[vertexId] = vectorVertex[vertexId].normal;
    }

    m_bInternalData = true;
  }
  else
  {
    m_bInternalData = false;
  }
}

 /*****************************************************************************/
/** Returns the core material ID.
  *
  * This function returns the core material ID of the submesh instance.
  *
  * @return One of the following values:
  *         \li the \b ID of the core material
  *         \li \b -1 if an error happend
  *****************************************************************************/

int CalSubmesh::getCoreMaterialId() const
{
  return m_coreMaterialId;
}

 /*****************************************************************************/
/** Provides access to the core submesh.
  *
  * This function returns the core submesh on which this submesh instance is
  * based on.
  *
  * @return One of the following values:
  *         \li a pointer to the core submesh
  *         \li \b 0 if an error happend
  *****************************************************************************/

CalCoreSubmesh *CalSubmesh::getCoreSubmesh()
{
  return m_pCoreSubmesh;
}

 /*****************************************************************************/
/** Returns the number of faces.
  *
  * This function returns the number of faces in the submesh instance.
  *
  * @return The number of faces.
  *****************************************************************************/

int CalSubmesh::getFaceCount() const
{
  return m_faceCount;
}

 /*****************************************************************************/
/** Provides access to the face data.
  *
  * This function returns the face data (vertex indices) of the submesh
  * instance. The LOD setting of the submesh instance is taken into account.
  *
  * @param pFaceBuffer A pointer to the user-provided buffer where the face
  *                    data is written to.
  *
  * @return The number of faces written to the buffer.
  *****************************************************************************/
int CalSubmesh::getFaces(CalIndex *pFaceBuffer)
{
  // copy the face vector to the face buffer
  memcpy(pFaceBuffer, &m_vectorFace[0], m_faceCount * sizeof(Face));

  return m_faceCount;
}

 /*****************************************************************************/
/** Returns the normal vector.
  *
  * This function returns the vector that contains all normals of the submesh
  * instance.
  *
  * @return A reference to the normal vector.
  *****************************************************************************/

std::vector<CalVector>& CalSubmesh::getVectorNormal()
{
  return m_vectorNormal;
}

   /*****************************************************************************/
/** Returns the tangent space vector-vector.
  *
  * This function returns the vector that contains all tangent space bases of
  * the submesh instance. This vector contains another vector
  * because there can be more than one texture map at each vertex.
  *
  * @return A reference to the tangent space vector-vector.
  *****************************************************************************/

std::vector<std::vector<CalSubmesh::TangentSpace> >& CalSubmesh::getVectorVectorTangentSpace()
{
  return m_vectorvectorTangentSpace;
}

 /*****************************************************************************/
/** Returns the physical property vector.
  *
  * This function returns the vector that contains all physical properties of
  * the submesh instance.
  *
  * @return A reference to the physical property vector.
  *****************************************************************************/

std::vector<CalSubmesh::PhysicalProperty>& CalSubmesh::getVectorPhysicalProperty()
{
  return m_vectorPhysicalProperty;
}

 /*****************************************************************************/
/** Returns the vertex vector.
  *
  * This function returns the vector that contains all vertices of the submesh
  * instance.
  *
  * @return A reference to the vertex vector.
  *****************************************************************************/

std::vector<CalVector>& CalSubmesh::getVectorVertex()
{
  return m_vectorVertex;
}

 /*****************************************************************************/
/** Returns the number of vertices.
  *
  * This function returns the number of vertices in the submesh instance.
  *
  * @return The number of vertices.
  *****************************************************************************/

int CalSubmesh::getVertexCount() const
{
  return m_vertexCount;
}

 /*****************************************************************************/
/** Returns if the submesh instance handles vertex data internally.
  *
  * This function returns wheter the submesh instance handles vertex data
  * internally.
  *
  * @return One of the following values:
  *         \li \b true if vertex data is handled internally
  *         \li \b false if not
  *****************************************************************************/

bool CalSubmesh::hasInternalData() const
{
  return m_bInternalData;
}

/*****************************************************************************/
/** Disable internal data (and thus springs system)
  *
  *****************************************************************************/

void CalSubmesh::disableInternalData()
{
  if(m_bInternalData)
  {
    m_vectorVertex.clear();
    m_vectorNormal.clear();
    m_vectorvectorTangentSpace.clear();
    m_vectorPhysicalProperty.clear();
    m_bInternalData=false;
  }

}

 /*****************************************************************************/
/** Returns true if tangent vectors are enabled.
  *
  * This function returns true if the submesh contains tangent vectors.
  *
  * @return True if tangent vectors are enabled.
  *****************************************************************************/

bool CalSubmesh::isTangentsEnabled(int mapId) const
{
	return m_pCoreSubmesh->isTangentsEnabled(mapId);
}

 /*****************************************************************************/
/** Enables (and calculates) or disables the storage of tangent spaces.
  *
  * This function enables or disables the storage of tangent space bases.
  *****************************************************************************/

bool CalSubmesh::enableTangents(int mapId, bool enabled)
{
  if(!m_pCoreSubmesh->enableTangents(mapId,enabled))
    return false;

  if(!m_bInternalData)
    return true;

  if(!enabled)
  {
    m_vectorvectorTangentSpace[mapId].clear();
    return true;
  }

  m_vectorvectorTangentSpace[mapId].reserve(m_pCoreSubmesh->getVertexCount());
  m_vectorvectorTangentSpace[mapId].resize(m_pCoreSubmesh->getVertexCount());

  // get the tangent space vector of the core submesh
  std::vector<CalCoreSubmesh::TangentSpace >& vectorTangentSpace = m_pCoreSubmesh->getVectorVectorTangentSpace()[mapId];

  // copy the data from the core submesh as default values
  int vertexId;
  for(vertexId = 0; vertexId < m_pCoreSubmesh->getVertexCount(); vertexId++)
  {
    // copy the tangent space data
    m_vectorvectorTangentSpace[mapId][vertexId].tangent=vectorTangentSpace[vertexId].tangent;
    m_vectorvectorTangentSpace[mapId][vertexId].crossFactor=vectorTangentSpace[vertexId].crossFactor;
  }

  return true;
}

 /*****************************************************************************/
/** Sets the core material ID.
  *
  * This function sets the core material ID of the submesh instance.
  *
  * @param coreMaterialId The core material ID that should be set.
  *****************************************************************************/

void CalSubmesh::setCoreMaterialId(int coreMaterialId)
{
  m_coreMaterialId = coreMaterialId;
}

 /*****************************************************************************/
/** Sets the LOD level.
  *
  * This function sets the LOD level of the submesh instance.
  *
  * @param lodLevel The LOD level in the range [0.0, 1.0].
  *****************************************************************************/

void CalSubmesh::setLodLevel(float lodLevel)
{
  // clamp the lod level to [0.0, 1.0]
  if(lodLevel < 0.0f) lodLevel = 0.0f;
  if(lodLevel > 1.0f) lodLevel = 1.0f;

  // get the lod count of the core submesh
  int lodCount;
  lodCount = m_pCoreSubmesh->getLodCount();

  // calculate the target lod count
  lodCount = (int)((1.0f - lodLevel) * lodCount);

  // calculate the new number of vertices
  m_vertexCount = m_pCoreSubmesh->getVertexCount() - lodCount;

  // get face vector of the core submesh
  std::vector<CalCoreSubmesh::Face>& vectorFace = m_pCoreSubmesh->getVectorFace();

  // get face vector of the core submesh
  std::vector<CalCoreSubmesh::Vertex>& vectorVertex = m_pCoreSubmesh->getVectorVertex();

  // calculate the new number of faces
  m_faceCount = vectorFace.size();

  int vertexId;
  for(vertexId = vectorVertex.size() - 1; vertexId >= m_vertexCount; vertexId--)
  {
    m_faceCount -= vectorVertex[vertexId].faceCollapseCount;
  }

  // fill the face vector with the collapsed vertex ids
  int faceId;
  for(faceId = 0; faceId < m_faceCount; ++faceId)
  {
    int vertexId;
    for(vertexId = 0; vertexId < 3; ++vertexId)
    {
      // get the vertex id
      CalIndex collapsedVertexId;
      collapsedVertexId = vectorFace[faceId].vertexId[vertexId];

      // collapse the vertex id until it fits into the current lod level
      while(collapsedVertexId >= m_vertexCount) collapsedVertexId = vectorVertex[collapsedVertexId].collapseId;

      // store the collapse vertex id in the submesh face vector
      m_vectorFace[faceId].vertexId[vertexId] = collapsedVertexId;
    }
  }
}

 /*****************************************************************************/
/** Sets weight of a morph target with the given id.
  *
  * @param blendId The morph target id.
  * @param weight The weight to be set.
  *****************************************************************************/

void CalSubmesh::setMorphTargetWeight(int blendId,float weight)
{
  m_vectorMorphTargetWeight[blendId] = weight;
}

 /*****************************************************************************/
/** Gets weight of a morph target with the given id.
  *
  * @param blendId The morph target id.
  * @return The weight of the morph target.
  *****************************************************************************/

float CalSubmesh::getMorphTargetWeight(int blendId) const
{
  return m_vectorMorphTargetWeight[blendId];
}

 /*****************************************************************************/
/** Gets weight of the base vertices.
  *
  * @return The weight of the base vertices.
  *****************************************************************************/

float CalSubmesh::getBaseWeight() const
{
  float baseWeight = 1.0f;
  int morphTargetCount = getMorphTargetWeightCount();
  int morphTargetId;
  for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId)
  {
    baseWeight -= m_vectorMorphTargetWeight[morphTargetId];
  }
  return baseWeight;
}

 /*****************************************************************************/
/** Returns the morph target weight vector.
  *
  * This function returns the vector that contains all weights for
  * each morph target instance.
  *
  * @return A reference to the weight vector.
  *****************************************************************************/
std::vector<float>& CalSubmesh::getVectorMorphTargetWeight()
{
  return m_vectorMorphTargetWeight;
}

 /*****************************************************************************/
/** Returns the number of weights.
  *
  * This function returns the number of weights.
  *
  * @return The number of weights.
  *****************************************************************************/

int CalSubmesh::getMorphTargetWeightCount() const
{
  return m_vectorMorphTargetWeight.size();
}

//****************************************************************************//
<commit_msg>Optimized setLodLevel.<commit_after>//****************************************************************************//
// submesh.cpp                                                                //
// Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
//****************************************************************************//
// This library is free software; you can redistribute it and/or modify it    //
// under the terms of the GNU Lesser General Public License as published by   //
// the Free Software Foundation; either version 2.1 of the License, or (at    //
// your option) any later version.                                            //
//****************************************************************************//

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "cal3d/submesh.h"
#include "cal3d/error.h"
#include "cal3d/coresubmesh.h"

CalSubmesh::CalSubmesh(CalCoreSubmesh* coreSubmesh)
{
  assert(coreSubmesh);

  m_pCoreSubmesh = coreSubmesh;

  // reserve memory for the face vector
  m_vectorFace.reserve(m_pCoreSubmesh->getFaceCount());
  m_vectorFace.resize(m_pCoreSubmesh->getFaceCount());

  // set the initial lod level
  setLodLevel(1.0f);

  // set the initial material id
  m_coreMaterialId = -1;

  //Setting the morph target weights
  m_vectorMorphTargetWeight.reserve(m_pCoreSubmesh->getCoreSubMorphTargetCount());
  m_vectorMorphTargetWeight.resize(m_pCoreSubmesh->getCoreSubMorphTargetCount());
  int morphTargetId;
  for(morphTargetId = 0; morphTargetId<m_pCoreSubmesh->getCoreSubMorphTargetCount();++morphTargetId)
  {
    m_vectorMorphTargetWeight[morphTargetId] = 0.0f;
  }

  // check if the submesh instance must handle the vertex and normal data internally
  if(m_pCoreSubmesh->getSpringCount() > 0)
  {
    m_vectorVertex.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorVertex.resize(m_pCoreSubmesh->getVertexCount());
    m_vectorNormal.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorNormal.resize(m_pCoreSubmesh->getVertexCount());

    m_vectorvectorTangentSpace.reserve(m_pCoreSubmesh->getVectorVectorTangentSpace().size());
    m_vectorvectorTangentSpace.resize(m_pCoreSubmesh->getVectorVectorTangentSpace().size());

    m_vectorPhysicalProperty.reserve(m_pCoreSubmesh->getVertexCount());
    m_vectorPhysicalProperty.resize(m_pCoreSubmesh->getVertexCount());

    // get the vertex vector of the core submesh
    std::vector<CalCoreSubmesh::Vertex>& vectorVertex = m_pCoreSubmesh->getVectorVertex();

    // copy the data from the core submesh as default values
    int vertexId;
    for(vertexId = 0; vertexId < m_pCoreSubmesh->getVertexCount(); ++vertexId)
    {
      // copy the vertex data
      m_vectorVertex[vertexId] = vectorVertex[vertexId].position;
      m_vectorPhysicalProperty[vertexId].position = vectorVertex[vertexId].position;
      m_vectorPhysicalProperty[vertexId].positionOld = vectorVertex[vertexId].position;

      // copy the normal data
      m_vectorNormal[vertexId] = vectorVertex[vertexId].normal;
    }

    m_bInternalData = true;
  }
  else
  {
    m_bInternalData = false;
  }
}

 /*****************************************************************************/
/** Returns the core material ID.
  *
  * This function returns the core material ID of the submesh instance.
  *
  * @return One of the following values:
  *         \li the \b ID of the core material
  *         \li \b -1 if an error happend
  *****************************************************************************/

int CalSubmesh::getCoreMaterialId() const
{
  return m_coreMaterialId;
}

 /*****************************************************************************/
/** Provides access to the core submesh.
  *
  * This function returns the core submesh on which this submesh instance is
  * based on.
  *
  * @return One of the following values:
  *         \li a pointer to the core submesh
  *         \li \b 0 if an error happend
  *****************************************************************************/

CalCoreSubmesh *CalSubmesh::getCoreSubmesh()
{
  return m_pCoreSubmesh;
}

 /*****************************************************************************/
/** Returns the number of faces.
  *
  * This function returns the number of faces in the submesh instance.
  *
  * @return The number of faces.
  *****************************************************************************/

int CalSubmesh::getFaceCount() const
{
  return m_faceCount;
}

 /*****************************************************************************/
/** Provides access to the face data.
  *
  * This function returns the face data (vertex indices) of the submesh
  * instance. The LOD setting of the submesh instance is taken into account.
  *
  * @param pFaceBuffer A pointer to the user-provided buffer where the face
  *                    data is written to.
  *
  * @return The number of faces written to the buffer.
  *****************************************************************************/
int CalSubmesh::getFaces(CalIndex *pFaceBuffer)
{
  // copy the face vector to the face buffer
  memcpy(pFaceBuffer, &m_vectorFace[0], m_faceCount * sizeof(Face));

  return m_faceCount;
}

 /*****************************************************************************/
/** Returns the normal vector.
  *
  * This function returns the vector that contains all normals of the submesh
  * instance.
  *
  * @return A reference to the normal vector.
  *****************************************************************************/

std::vector<CalVector>& CalSubmesh::getVectorNormal()
{
  return m_vectorNormal;
}

   /*****************************************************************************/
/** Returns the tangent space vector-vector.
  *
  * This function returns the vector that contains all tangent space bases of
  * the submesh instance. This vector contains another vector
  * because there can be more than one texture map at each vertex.
  *
  * @return A reference to the tangent space vector-vector.
  *****************************************************************************/

std::vector<std::vector<CalSubmesh::TangentSpace> >& CalSubmesh::getVectorVectorTangentSpace()
{
  return m_vectorvectorTangentSpace;
}

 /*****************************************************************************/
/** Returns the physical property vector.
  *
  * This function returns the vector that contains all physical properties of
  * the submesh instance.
  *
  * @return A reference to the physical property vector.
  *****************************************************************************/

std::vector<CalSubmesh::PhysicalProperty>& CalSubmesh::getVectorPhysicalProperty()
{
  return m_vectorPhysicalProperty;
}

 /*****************************************************************************/
/** Returns the vertex vector.
  *
  * This function returns the vector that contains all vertices of the submesh
  * instance.
  *
  * @return A reference to the vertex vector.
  *****************************************************************************/

std::vector<CalVector>& CalSubmesh::getVectorVertex()
{
  return m_vectorVertex;
}

 /*****************************************************************************/
/** Returns the number of vertices.
  *
  * This function returns the number of vertices in the submesh instance.
  *
  * @return The number of vertices.
  *****************************************************************************/

int CalSubmesh::getVertexCount() const
{
  return m_vertexCount;
}

 /*****************************************************************************/
/** Returns if the submesh instance handles vertex data internally.
  *
  * This function returns wheter the submesh instance handles vertex data
  * internally.
  *
  * @return One of the following values:
  *         \li \b true if vertex data is handled internally
  *         \li \b false if not
  *****************************************************************************/

bool CalSubmesh::hasInternalData() const
{
  return m_bInternalData;
}

/*****************************************************************************/
/** Disable internal data (and thus springs system)
  *
  *****************************************************************************/

void CalSubmesh::disableInternalData()
{
  if(m_bInternalData)
  {
    m_vectorVertex.clear();
    m_vectorNormal.clear();
    m_vectorvectorTangentSpace.clear();
    m_vectorPhysicalProperty.clear();
    m_bInternalData=false;
  }

}

 /*****************************************************************************/
/** Returns true if tangent vectors are enabled.
  *
  * This function returns true if the submesh contains tangent vectors.
  *
  * @return True if tangent vectors are enabled.
  *****************************************************************************/

bool CalSubmesh::isTangentsEnabled(int mapId) const
{
	return m_pCoreSubmesh->isTangentsEnabled(mapId);
}

 /*****************************************************************************/
/** Enables (and calculates) or disables the storage of tangent spaces.
  *
  * This function enables or disables the storage of tangent space bases.
  *****************************************************************************/

bool CalSubmesh::enableTangents(int mapId, bool enabled)
{
  if(!m_pCoreSubmesh->enableTangents(mapId,enabled))
    return false;

  if(!m_bInternalData)
    return true;

  if(!enabled)
  {
    m_vectorvectorTangentSpace[mapId].clear();
    return true;
  }

  m_vectorvectorTangentSpace[mapId].reserve(m_pCoreSubmesh->getVertexCount());
  m_vectorvectorTangentSpace[mapId].resize(m_pCoreSubmesh->getVertexCount());

  // get the tangent space vector of the core submesh
  std::vector<CalCoreSubmesh::TangentSpace >& vectorTangentSpace = m_pCoreSubmesh->getVectorVectorTangentSpace()[mapId];

  // copy the data from the core submesh as default values
  int vertexId;
  for(vertexId = 0; vertexId < m_pCoreSubmesh->getVertexCount(); vertexId++)
  {
    // copy the tangent space data
    m_vectorvectorTangentSpace[mapId][vertexId].tangent=vectorTangentSpace[vertexId].tangent;
    m_vectorvectorTangentSpace[mapId][vertexId].crossFactor=vectorTangentSpace[vertexId].crossFactor;
  }

  return true;
}

 /*****************************************************************************/
/** Sets the core material ID.
  *
  * This function sets the core material ID of the submesh instance.
  *
  * @param coreMaterialId The core material ID that should be set.
  *****************************************************************************/

void CalSubmesh::setCoreMaterialId(int coreMaterialId)
{
  m_coreMaterialId = coreMaterialId;
}

 /*****************************************************************************/
/** Sets the LOD level.
  *
  * This function sets the LOD level of the submesh instance.
  *
  * @param lodLevel The LOD level in the range [0.0, 1.0].
  *****************************************************************************/

void CalSubmesh::setLodLevel(float lodLevel)
{
  // clamp the lod level to [0.0, 1.0]
  if(lodLevel < 0.0f) lodLevel = 0.0f;
  if(lodLevel > 1.0f) lodLevel = 1.0f;

  // get the lod count of the core submesh
  int lodCount;
  lodCount = m_pCoreSubmesh->getLodCount();

  // calculate the target lod count
  lodCount = (int)((1.0f - lodLevel) * lodCount);

  // get vertex vector of the core submesh
  std::vector<CalCoreSubmesh::Vertex>& vectorVertex = m_pCoreSubmesh->getVectorVertex();
  int coreVertexCount = vectorVertex.size();
  const CalCoreSubmesh::Vertex*	coreVertexPtr = &vectorVertex[0];

  // calculate the new number of vertices
  m_vertexCount = coreVertexCount - lodCount;

  // get face vector of the core submesh
  std::vector<CalCoreSubmesh::Face>& vectorFace = m_pCoreSubmesh->getVectorFace();
  const CalCoreSubmesh::Face* coreFacePtr = &vectorFace[0];

  // calculate the new number of faces
  m_faceCount = vectorFace.size();

  int vertexId;
  for(vertexId = coreVertexCount - 1; vertexId >= m_vertexCount; --vertexId)
  {
    m_faceCount -= coreVertexPtr[vertexId].faceCollapseCount;
  }

  // fill the face vector with the collapsed vertex ids
  int faceId;
  Face*	myFacePtr = &m_vectorFace[0];
  for(faceId = 0; faceId < m_faceCount; ++faceId)
  {
    int vertexId;
    for(vertexId = 0; vertexId < 3; ++vertexId)
    {
      // get the vertex id
      CalIndex collapsedVertexId;
      collapsedVertexId = coreFacePtr[faceId].vertexId[vertexId];

      // collapse the vertex id until it fits into the current lod level
      while(collapsedVertexId >= m_vertexCount)
		collapsedVertexId = coreVertexPtr[collapsedVertexId].collapseId;

      // store the collapse vertex id in the submesh face vector
      myFacePtr[faceId].vertexId[vertexId] = collapsedVertexId;
    }
  }
}

 /*****************************************************************************/
/** Sets weight of a morph target with the given id.
  *
  * @param blendId The morph target id.
  * @param weight The weight to be set.
  *****************************************************************************/

void CalSubmesh::setMorphTargetWeight(int blendId,float weight)
{
  m_vectorMorphTargetWeight[blendId] = weight;
}

 /*****************************************************************************/
/** Gets weight of a morph target with the given id.
  *
  * @param blendId The morph target id.
  * @return The weight of the morph target.
  *****************************************************************************/

float CalSubmesh::getMorphTargetWeight(int blendId) const
{
  return m_vectorMorphTargetWeight[blendId];
}

 /*****************************************************************************/
/** Gets weight of the base vertices.
  *
  * @return The weight of the base vertices.
  *****************************************************************************/

float CalSubmesh::getBaseWeight() const
{
  float baseWeight = 1.0f;
  int morphTargetCount = getMorphTargetWeightCount();
  int morphTargetId;
  for(morphTargetId=0; morphTargetId < morphTargetCount;++morphTargetId)
  {
    baseWeight -= m_vectorMorphTargetWeight[morphTargetId];
  }
  return baseWeight;
}

 /*****************************************************************************/
/** Returns the morph target weight vector.
  *
  * This function returns the vector that contains all weights for
  * each morph target instance.
  *
  * @return A reference to the weight vector.
  *****************************************************************************/
std::vector<float>& CalSubmesh::getVectorMorphTargetWeight()
{
  return m_vectorMorphTargetWeight;
}

 /*****************************************************************************/
/** Returns the number of weights.
  *
  * This function returns the number of weights.
  *
  * @return The number of weights.
  *****************************************************************************/

int CalSubmesh::getMorphTargetWeightCount() const
{
  return m_vectorMorphTargetWeight.size();
}

//****************************************************************************//
<|endoftext|>