<commit_before>// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
 * Interface to manage the Bullet3 physics library.
 *
 * License: Mozilla Public License Version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/ OR See accompanying file LICENSE)
 * Authors:
 *  - Dan Printzell
 */
#include <hydra/system/bulletphysicssystem.hpp>

#include <memory>

#include <hydra/component/rigidbodycomponent.hpp>
#include <hydra/component/ghostobjectcomponent.hpp>
#include <hydra/component/particlecomponent.hpp>
#include <hydra/component/bulletcomponent.hpp>
#include <hydra/component/lifecomponent.hpp>
#include <hydra/component/playercomponent.hpp>
#include <hydra/component/pickupcomponent.hpp>
#include <hydra/component/perkcomponent.hpp>
#include <hydra/component/textcomponent.hpp>
#include <hydra/component/ghostobjectcomponent.hpp>
#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btGhostObject.h>

inline static btQuaternion cast(const glm::quat& r) { return btQuaternion{r.x, r.y, r.z, r.w}; }
inline static btVector3 cast(const glm::vec3& v) { return btVector3{v.x, v.y, v.z}; }

inline static glm::quat cast(const btQuaternion& r) { return glm::quat(r.w(), r.x(), r.y(), r.z()); }
inline static glm::vec3 cast(const btVector3& v) { return glm::vec3(v.x(), v.y(), v.z()); }

using namespace Hydra::System;
using namespace Hydra::Component;

struct BulletPhysicsSystem::Data {
	std::unique_ptr<btDefaultCollisionConfiguration> config;
	std::unique_ptr<btCollisionDispatcher> dispatcher;
	std::unique_ptr<btBroadphaseInterface> broadphase;
	std::unique_ptr<btSequentialImpulseConstraintSolver> solver;
	std::unique_ptr<btDiscreteDynamicsWorld> dynamicsWorld;
};

BulletPhysicsSystem::BulletPhysicsSystem() {
	_data = new Data;
	_data->config = std::make_unique<btDefaultCollisionConfiguration>();
	_data->dispatcher = std::make_unique<btCollisionDispatcher>(_data->config.get());
	_data->broadphase = std::make_unique<btDbvtBroadphase>();
	_data->solver = std::make_unique<btSequentialImpulseConstraintSolver>();
	_data->dynamicsWorld = std::make_unique<btDiscreteDynamicsWorld>(_data->dispatcher.get(), _data->broadphase.get(), _data->solver.get(), _data->config.get());
	_data->dynamicsWorld->setGravity(btVector3(0, -10, 0));
}

BulletPhysicsSystem::~BulletPhysicsSystem() { delete _data; }

void BulletPhysicsSystem::enable(RigidBodyComponent* component) {
	component->_handler = this;
	// Make so addRigidbody takes in collision filter group and what that group collides with.
	btRigidBody* rigidBody = static_cast<btRigidBody*>(component->getRigidBody());
	switch (rigidBody->getUserIndex2())
	{
	case CollisionTypes::COLL_PLAYER:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PLAYER, CollisionCondition::playerCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_ENEMY, CollisionCondition::enemyCollidesWith);
		break;
	case CollisionTypes::COLL_WALL:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_WALL, CollisionCondition::wallCollidesWith);
		break;
	case CollisionTypes::COLL_PLAYER_PROJECTILE:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PLAYER_PROJECTILE, CollisionCondition::playerProjCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY_PROJECTILE:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_ENEMY_PROJECTILE, CollisionCondition::enemyProjCollidesWith);
		break;
	case CollisionTypes::COLL_MISC_OBJECT:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_MISC_OBJECT, CollisionCondition::miscObjectCollidesWith);
		break;
	case CollisionTypes::COLL_PICKUP_OBJECT:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PICKUP_OBJECT, CollisionCondition::pickupObjectCollidesWith);
		break;
	default:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_NOTHING, COLL_NOTHING);
		break;
	}
}

void BulletPhysicsSystem::disable(RigidBodyComponent* component) {
	_data->dynamicsWorld->removeRigidBody(static_cast<btRigidBody*>(component->getRigidBody()));
	component->_handler = nullptr;
}

void Hydra::System::BulletPhysicsSystem::enable(GhostObjectComponent * component){
	component->_handler = this;

	switch (component->ghostObject->getUserIndex2())
	{
	case CollisionTypes::COLL_PLAYER:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PLAYER, CollisionCondition::playerCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_ENEMY, CollisionCondition::enemyCollidesWith);
		break;
	case CollisionTypes::COLL_WALL:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_WALL, CollisionCondition::wallCollidesWith);
		break;
	case CollisionTypes::COLL_PLAYER_PROJECTILE:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PLAYER_PROJECTILE, CollisionCondition::playerProjCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY_PROJECTILE:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_ENEMY_PROJECTILE, CollisionCondition::enemyProjCollidesWith);
		break;
	case CollisionTypes::COLL_MISC_OBJECT:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_MISC_OBJECT, CollisionCondition::miscObjectCollidesWith);
		break;
	case CollisionTypes::COLL_PICKUP_OBJECT:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PICKUP_OBJECT, CollisionCondition::pickupObjectCollidesWith);
		break;
	default:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_NOTHING, COLL_NOTHING);
		break;
	}
}

void Hydra::System::BulletPhysicsSystem::disable(GhostObjectComponent * component){
	_data->dynamicsWorld->removeCollisionObject(component->ghostObject);
	component->_handler = nullptr;
}

void BulletPhysicsSystem::tick(float delta) {
	_data->dynamicsWorld->stepSimulation(delta, 3);
	// Gets all collisions happening between all rigidbody entities.
	//_data->dynamicsWorld->stepSimulation(delta, 3, btScalar(1.0) / btScalar(180.));
	int numManifolds = _data->dynamicsWorld->getDispatcher()->getNumManifolds();
	for (int i = 0; i < numManifolds; i++) {
		btPersistentManifold* contactManifold = _data->dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
		const btCollisionObject* obA = contactManifold->getBody0();
		const btCollisionObject* obB = contactManifold->getBody1();
		Entity* eA = Hydra::World::World::getEntity(obA->getUserIndex()).get();
		Entity* eB = Hydra::World::World::getEntity(obB->getUserIndex()).get();

		if (!eA || !eB)
			continue;

		BulletComponent* bulletComponent = nullptr;
		LifeComponent* lifeComponent = nullptr;
		PlayerComponent* playerComponent = nullptr;
		PickUpComponent* pickupComponent = nullptr;
		PerkComponent* perkComponent = nullptr;

		if ((bulletComponent = eA->getComponent<BulletComponent>().get()))
			lifeComponent = eB->getComponent<LifeComponent>().get();
		else if ((bulletComponent = eB->getComponent<BulletComponent>().get()))
			lifeComponent = eA->getComponent<LifeComponent>().get();

		playerComponent = eA->getComponent<PlayerComponent>().get();
		if (!playerComponent)
			playerComponent = eB->getComponent<PlayerComponent>().get();

		if ((pickupComponent = eA->getComponent<PickUpComponent>().get()))
			perkComponent = eB->getComponent<PerkComponent>().get();
		else if ((pickupComponent = eB->getComponent<PickUpComponent>().get()))
			perkComponent = eA->getComponent<PerkComponent>().get();

		if (pickupComponent && perkComponent) {
			_addPickUp(pickupComponent, perkComponent);
			_spawnDamageText(Hydra::World::World::getEntity(playerComponent->entityID)->getComponent<Hydra::Component::TransformComponent>()->position, "eyyy\n");
		}

		// Gets the contact points
		int numContacts = contactManifold->getNumContacts();
		for (int j = 0; j < numContacts; j++) {
			btManifoldPoint& pt = contactManifold->getContactPoint(j);
			btVector3 collPosB = pt.getPositionWorldOnB();
			btVector3 normalOnB = pt.m_normalWorldOnB;

			if (playerComponent && normalOnB.y() > 0.7){
				playerComponent->onGround = true;
			}

			if (lifeComponent) {
				lifeComponent->applyDamage(bulletComponent->damage);

				_spawnDamageText(cast(collPosB), std::to_string(bulletComponent->damage));
			}

			// Set the bullet entity to dead.
			if (bulletComponent) {
				World::World::World::getEntity(bulletComponent->entityID)->dead = true;
				_spawnParticleEmitterAt(cast(collPosB), cast(normalOnB));
			}

			// Breaks because just wanna check the first collision.
			break;
		}
	}

	entities.clear();
}

void BulletPhysicsSystem::_spawnParticleEmitterAt(const glm::vec3& pos, const glm::vec3& normal) {
	auto pE = Hydra::World::World::newEntity("Collision Particle Spawner", Hydra::World::World::rootID);

	pE->addComponent<MeshComponent>()->loadMesh("PARTICLEQUAD");

	auto pETC = pE->addComponent<TransformComponent>();
	pETC->position = pos;

	auto pEPC = pE->addComponent<Hydra::Component::ParticleComponent>();
	pEPC->delay = 1.0f / 2.0f;
	pEPC->accumulator = 2 * 5.0f;
	pEPC->tempVelocity = glm::vec3(6.0f, 6.0f, 6.0f);
	pEPC->behaviour = Hydra::Component::ParticleComponent::EmitterBehaviour::Explosion;
	pEPC->texture = Hydra::Component::ParticleComponent::ParticleTexture::Blood;
	pEPC->optionalNormal = normal;

	auto pELC = pE->addComponent<LifeComponent>();
	pELC->maxHP = 0.9f;
	pELC->health = 0.9f;
}

void BulletPhysicsSystem::_spawnDamageText(const glm::vec3& pos, const std::string& text) {
	auto textEntity = world::newEntity("Damage", world::root());
	auto transC = textEntity->addComponent<TransformComponent>();
	transC->setPosition(pos);
	transC->setScale(glm::vec3(10));
	textEntity->addComponent<MeshComponent>()->loadMesh("TEXTQUAD");
	auto lifeC = textEntity->addComponent<LifeComponent>();
	lifeC->health = lifeC->maxHP = 2;
	auto textC = textEntity->addComponent<TextComponent>();
	//char buff[64];
	//snprintf(buff, sizeof(buff), "%.0f\x01\x02", text);
	textC->setText(text.substr(0, 1));
	textC->isStatic = false;
}

void Hydra::System::BulletPhysicsSystem::_addPickUp(PickUpComponent * pickupComponent, PerkComponent * perkComponent)
{
	switch (pickupComponent->pickUpType)
	{
	case PickUpComponent::PICKUP_RANDOMPERK: {
		std::vector<int> perksNotFound;

		for (size_t i = 0; i < perkComponent->AMOUNTOFPERKS; i++){
			bool perkFound = false;
			for (size_t j = 0; j < perkComponent->activePerks.size(); j++){
				if (PerkComponent::Perk(i) == perkComponent->activePerks[j]){
					perkFound = true;
					j = perkComponent->activePerks.size();
				}
			}
			for (size_t j = 0; j < perkComponent->newPerks.size(); j++){
				if (PerkComponent::Perk(i) == perkComponent->newPerks[j]) {
					perkFound = true;
					j = perkComponent->newPerks.size();
				}
			}
			if (!perkFound)
				perksNotFound.push_back(i);
		}

		if (!perksNotFound.empty()){
			int newPerk = rand() % (perksNotFound.size());
			perkComponent->newPerks.push_back(PerkComponent::Perk(perksNotFound[newPerk]));
		}

		World::World::World::getEntity(pickupComponent->entityID)->dead = true;
	}
		break;
	case PickUpComponent::PICKUP_HEALTH: {

	}
		break;
	case PickUpComponent::PICKUP_AMMO: {

	}
		break;
	default:
		break;
	}
}

void BulletPhysicsSystem::registerUI() {}
<commit_msg>substr fix<commit_after>// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/**
 * Interface to manage the Bullet3 physics library.
 *
 * License: Mozilla Public License Version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/ OR See accompanying file LICENSE)
 * Authors:
 *  - Dan Printzell
 */
#include <hydra/system/bulletphysicssystem.hpp>

#include <memory>

#include <hydra/component/rigidbodycomponent.hpp>
#include <hydra/component/ghostobjectcomponent.hpp>
#include <hydra/component/particlecomponent.hpp>
#include <hydra/component/bulletcomponent.hpp>
#include <hydra/component/lifecomponent.hpp>
#include <hydra/component/playercomponent.hpp>
#include <hydra/component/pickupcomponent.hpp>
#include <hydra/component/perkcomponent.hpp>
#include <hydra/component/textcomponent.hpp>
#include <hydra/component/ghostobjectcomponent.hpp>
#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btGhostObject.h>

inline static btQuaternion cast(const glm::quat& r) { return btQuaternion{r.x, r.y, r.z, r.w}; }
inline static btVector3 cast(const glm::vec3& v) { return btVector3{v.x, v.y, v.z}; }

inline static glm::quat cast(const btQuaternion& r) { return glm::quat(r.w(), r.x(), r.y(), r.z()); }
inline static glm::vec3 cast(const btVector3& v) { return glm::vec3(v.x(), v.y(), v.z()); }

using namespace Hydra::System;
using namespace Hydra::Component;

struct BulletPhysicsSystem::Data {
	std::unique_ptr<btDefaultCollisionConfiguration> config;
	std::unique_ptr<btCollisionDispatcher> dispatcher;
	std::unique_ptr<btBroadphaseInterface> broadphase;
	std::unique_ptr<btSequentialImpulseConstraintSolver> solver;
	std::unique_ptr<btDiscreteDynamicsWorld> dynamicsWorld;
};

BulletPhysicsSystem::BulletPhysicsSystem() {
	_data = new Data;
	_data->config = std::make_unique<btDefaultCollisionConfiguration>();
	_data->dispatcher = std::make_unique<btCollisionDispatcher>(_data->config.get());
	_data->broadphase = std::make_unique<btDbvtBroadphase>();
	_data->solver = std::make_unique<btSequentialImpulseConstraintSolver>();
	_data->dynamicsWorld = std::make_unique<btDiscreteDynamicsWorld>(_data->dispatcher.get(), _data->broadphase.get(), _data->solver.get(), _data->config.get());
	_data->dynamicsWorld->setGravity(btVector3(0, -10, 0));
}

BulletPhysicsSystem::~BulletPhysicsSystem() { delete _data; }

void BulletPhysicsSystem::enable(RigidBodyComponent* component) {
	component->_handler = this;
	// Make so addRigidbody takes in collision filter group and what that group collides with.
	btRigidBody* rigidBody = static_cast<btRigidBody*>(component->getRigidBody());
	switch (rigidBody->getUserIndex2())
	{
	case CollisionTypes::COLL_PLAYER:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PLAYER, CollisionCondition::playerCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_ENEMY, CollisionCondition::enemyCollidesWith);
		break;
	case CollisionTypes::COLL_WALL:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_WALL, CollisionCondition::wallCollidesWith);
		break;
	case CollisionTypes::COLL_PLAYER_PROJECTILE:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PLAYER_PROJECTILE, CollisionCondition::playerProjCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY_PROJECTILE:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_ENEMY_PROJECTILE, CollisionCondition::enemyProjCollidesWith);
		break;
	case CollisionTypes::COLL_MISC_OBJECT:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_MISC_OBJECT, CollisionCondition::miscObjectCollidesWith);
		break;
	case CollisionTypes::COLL_PICKUP_OBJECT:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_PICKUP_OBJECT, CollisionCondition::pickupObjectCollidesWith);
		break;
	default:
		_data->dynamicsWorld->addRigidBody(rigidBody, COLL_NOTHING, COLL_NOTHING);
		break;
	}
}

void BulletPhysicsSystem::disable(RigidBodyComponent* component) {
	_data->dynamicsWorld->removeRigidBody(static_cast<btRigidBody*>(component->getRigidBody()));
	component->_handler = nullptr;
}

void Hydra::System::BulletPhysicsSystem::enable(GhostObjectComponent * component){
	component->_handler = this;

	switch (component->ghostObject->getUserIndex2())
	{
	case CollisionTypes::COLL_PLAYER:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PLAYER, CollisionCondition::playerCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_ENEMY, CollisionCondition::enemyCollidesWith);
		break;
	case CollisionTypes::COLL_WALL:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_WALL, CollisionCondition::wallCollidesWith);
		break;
	case CollisionTypes::COLL_PLAYER_PROJECTILE:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PLAYER_PROJECTILE, CollisionCondition::playerProjCollidesWith);
		break;
	case CollisionTypes::COLL_ENEMY_PROJECTILE:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_ENEMY_PROJECTILE, CollisionCondition::enemyProjCollidesWith);
		break;
	case CollisionTypes::COLL_MISC_OBJECT:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_MISC_OBJECT, CollisionCondition::miscObjectCollidesWith);
		break;
	case CollisionTypes::COLL_PICKUP_OBJECT:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_PICKUP_OBJECT, CollisionCondition::pickupObjectCollidesWith);
		break;
	default:
		_data->dynamicsWorld->addCollisionObject(component->ghostObject, COLL_NOTHING, COLL_NOTHING);
		break;
	}
}

void Hydra::System::BulletPhysicsSystem::disable(GhostObjectComponent * component){
	_data->dynamicsWorld->removeCollisionObject(component->ghostObject);
	component->_handler = nullptr;
}

void BulletPhysicsSystem::tick(float delta) {
	_data->dynamicsWorld->stepSimulation(delta, 3);
	// Gets all collisions happening between all rigidbody entities.
	//_data->dynamicsWorld->stepSimulation(delta, 3, btScalar(1.0) / btScalar(180.));
	int numManifolds = _data->dynamicsWorld->getDispatcher()->getNumManifolds();
	for (int i = 0; i < numManifolds; i++) {
		btPersistentManifold* contactManifold = _data->dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
		const btCollisionObject* obA = contactManifold->getBody0();
		const btCollisionObject* obB = contactManifold->getBody1();
		Entity* eA = Hydra::World::World::getEntity(obA->getUserIndex()).get();
		Entity* eB = Hydra::World::World::getEntity(obB->getUserIndex()).get();

		if (!eA || !eB)
			continue;

		BulletComponent* bulletComponent = nullptr;
		LifeComponent* lifeComponent = nullptr;
		PlayerComponent* playerComponent = nullptr;
		PickUpComponent* pickupComponent = nullptr;
		PerkComponent* perkComponent = nullptr;

		if ((bulletComponent = eA->getComponent<BulletComponent>().get()))
			lifeComponent = eB->getComponent<LifeComponent>().get();
		else if ((bulletComponent = eB->getComponent<BulletComponent>().get()))
			lifeComponent = eA->getComponent<LifeComponent>().get();

		playerComponent = eA->getComponent<PlayerComponent>().get();
		if (!playerComponent)
			playerComponent = eB->getComponent<PlayerComponent>().get();

		if ((pickupComponent = eA->getComponent<PickUpComponent>().get()))
			perkComponent = eB->getComponent<PerkComponent>().get();
		else if ((pickupComponent = eB->getComponent<PickUpComponent>().get()))
			perkComponent = eA->getComponent<PerkComponent>().get();

		if (pickupComponent && perkComponent) {
			_addPickUp(pickupComponent, perkComponent);
			_spawnDamageText(Hydra::World::World::getEntity(playerComponent->entityID)->getComponent<Hydra::Component::TransformComponent>()->position, "eyyy\n");
		}

		// Gets the contact points
		int numContacts = contactManifold->getNumContacts();
		for (int j = 0; j < numContacts; j++) {
			btManifoldPoint& pt = contactManifold->getContactPoint(j);
			btVector3 collPosB = pt.getPositionWorldOnB();
			btVector3 normalOnB = pt.m_normalWorldOnB;

			if (playerComponent && normalOnB.y() > 0.7){
				playerComponent->onGround = true;
			}

			if (lifeComponent) {
				lifeComponent->applyDamage(bulletComponent->damage);

				_spawnDamageText(cast(collPosB), std::to_string(bulletComponent->damage));
			}

			// Set the bullet entity to dead.
			if (bulletComponent) {
				World::World::World::getEntity(bulletComponent->entityID)->dead = true;
				_spawnParticleEmitterAt(cast(collPosB), cast(normalOnB));
			}

			// Breaks because just wanna check the first collision.
			break;
		}
	}

	entities.clear();
}

void BulletPhysicsSystem::_spawnParticleEmitterAt(const glm::vec3& pos, const glm::vec3& normal) {
	auto pE = Hydra::World::World::newEntity("Collision Particle Spawner", Hydra::World::World::rootID);

	pE->addComponent<MeshComponent>()->loadMesh("PARTICLEQUAD");

	auto pETC = pE->addComponent<TransformComponent>();
	pETC->position = pos;

	auto pEPC = pE->addComponent<Hydra::Component::ParticleComponent>();
	pEPC->delay = 1.0f / 2.0f;
	pEPC->accumulator = 2 * 5.0f;
	pEPC->tempVelocity = glm::vec3(6.0f, 6.0f, 6.0f);
	pEPC->behaviour = Hydra::Component::ParticleComponent::EmitterBehaviour::Explosion;
	pEPC->texture = Hydra::Component::ParticleComponent::ParticleTexture::Blood;
	pEPC->optionalNormal = normal;

	auto pELC = pE->addComponent<LifeComponent>();
	pELC->maxHP = 0.9f;
	pELC->health = 0.9f;
}

void BulletPhysicsSystem::_spawnDamageText(const glm::vec3& pos, const std::string& text) {
	auto textEntity = world::newEntity("Damage", world::root());
	auto transC = textEntity->addComponent<TransformComponent>();
	transC->setPosition(pos);
	transC->setScale(glm::vec3(10));
	textEntity->addComponent<MeshComponent>()->loadMesh("TEXTQUAD");
	auto lifeC = textEntity->addComponent<LifeComponent>();
	lifeC->health = lifeC->maxHP = 2;
	auto textC = textEntity->addComponent<TextComponent>();
	//char buff[64];
	//snprintf(buff, sizeof(buff), "%.0f\x01\x02", text);
	textC->setText(text.substr(0, 2));
	textC->isStatic = false;
}

void Hydra::System::BulletPhysicsSystem::_addPickUp(PickUpComponent * pickupComponent, PerkComponent * perkComponent)
{
	switch (pickupComponent->pickUpType)
	{
	case PickUpComponent::PICKUP_RANDOMPERK: {
		std::vector<int> perksNotFound;

		for (size_t i = 0; i < perkComponent->AMOUNTOFPERKS; i++){
			bool perkFound = false;
			for (size_t j = 0; j < perkComponent->activePerks.size(); j++){
				if (PerkComponent::Perk(i) == perkComponent->activePerks[j]){
					perkFound = true;
					j = perkComponent->activePerks.size();
				}
			}
			for (size_t j = 0; j < perkComponent->newPerks.size(); j++){
				if (PerkComponent::Perk(i) == perkComponent->newPerks[j]) {
					perkFound = true;
					j = perkComponent->newPerks.size();
				}
			}
			if (!perkFound)
				perksNotFound.push_back(i);
		}

		if (!perksNotFound.empty()){
			int newPerk = rand() % (perksNotFound.size());
			perkComponent->newPerks.push_back(PerkComponent::Perk(perksNotFound[newPerk]));
		}

		World::World::World::getEntity(pickupComponent->entityID)->dead = true;
	}
		break;
	case PickUpComponent::PICKUP_HEALTH: {

	}
		break;
	case PickUpComponent::PICKUP_AMMO: {

	}
		break;
	default:
		break;
	}
}

void BulletPhysicsSystem::registerUI() {}
<|endoftext|>


<commit_before>// This object encapsulates the 3D MRI data.
// Its job is to initialise the data,
//  take transform parameters,
// then provide slices and associated masks.

#ifndef MRI_HPP_
#define MRI_HPP_

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkResampleImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkChangeInformationImageFilter.h"
#include "itkImageMaskSpatialObject.h"
#include "itkImageRegionIterator.h"
#include "itkExtractImageFilter.h"

class MRI {
public:
	// unsigned char is native type, but multires can't handle unsigned types
  // typedef unsigned char PixelType;
  typedef short PixelType;
  typedef itk::Image< PixelType, 2 > SliceType;
	typedef itk::Image< unsigned char, 2 > MaskSliceType;
  typedef itk::Image< PixelType, 3 > VolumeType;
	typedef itk::Image< unsigned char, 3 > MaskVolumeType;
	typedef vector< SliceType::Pointer > SliceVectorType;
	typedef vector< MaskSliceType::Pointer > MaskSliceVectorType;
  typedef itk::ImageFileReader< VolumeType > ReaderType;
	typedef itk::RescaleIntensityImageFilter< VolumeType, VolumeType > RescaleIntensityFilterType;
	typedef itk::ChangeInformationImageFilter< VolumeType > ShrinkerType;
	typedef itk::ChangeInformationImageFilter< MaskVolumeType > MaskSpacerType;
	typedef itk::VersorRigid3DTransform< double > TransformType;
	typedef TransformType::ParametersType ParametersType;
  typedef itk::LinearInterpolateImageFunction< VolumeType, double > LinearInterpolatorType;
  typedef itk::NearestNeighborInterpolateImageFunction< MaskVolumeType, double > NearestNeighborInterpolatorType;
  typedef itk::ResampleImageFilter< VolumeType, VolumeType > ResamplerType;
  typedef itk::ResampleImageFilter< MaskVolumeType, MaskVolumeType > MaskResamplerType;
  typedef itk::ExtractImageFilter< VolumeType, SliceType > SliceExtractorType;
  typedef itk::ExtractImageFilter< MaskVolumeType, MaskSliceType > MaskSliceExtractorType;
  typedef itk::ImageRegionIterator< MaskVolumeType > IteratorType;
  typedef itk::ImageMaskSpatialObject< 3 > MaskType3D;
  typedef itk::ImageMaskSpatialObject< 2 > MaskType2D;
	typedef vector< MaskType2D::Pointer > MaskVectorType2D;

	VolumeType::Pointer originalImage;
	MaskVolumeType::Pointer originalMask;
  SliceVectorType slices;
  MaskSliceVectorType maskSlices;
	MaskType3D::Pointer mask3D;
  MaskVectorType2D masks2D;
  TransformType::Pointer transform;
  LinearInterpolatorType::Pointer linearInterpolator;
	NearestNeighborInterpolatorType::Pointer nearestNeighborInterpolator;
	RescaleIntensityFilterType::Pointer intensityRescaler;
	ShrinkerType::Pointer resizer;
	MaskSpacerType::Pointer maskSpacer;
  ResamplerType::Pointer resampler;
  VolumeType::SpacingType resamplerSpacing;
  VolumeType::SizeType resamplerSize;
  MaskResamplerType::Pointer maskResampler;
  SliceExtractorType::Pointer sliceExtractor;
  MaskSliceExtractorType::Pointer maskSliceExtractor;

	MRI(char const *inputFileName, VolumeType::SpacingType spacing, VolumeType::SizeType size, double initialResizeFactor):
	  resamplerSpacing(spacing),
	  resamplerSize(size) {
		readFile(inputFileName);
		rescaleIntensity();
		resizeImage(initialResizeFactor);
		buildOriginalMaskVolume();
    initialiseFilters();
    buildSlices();
    buildMaskSlices();
	}

	void readFile(char const *inputFileName) {
	  ReaderType::Pointer volumeReader = ReaderType::New();
		volumeReader->SetFileName( inputFileName );
    volumeReader->Update();
		originalImage = volumeReader->GetOutput();
	}

	void rescaleIntensity() {
		intensityRescaler = RescaleIntensityFilterType::New();
		intensityRescaler->SetOutputMinimum( 0 );
		intensityRescaler->SetOutputMaximum( 255 );
		intensityRescaler->SetInput( originalImage );
		intensityRescaler->Update();
		originalImage = intensityRescaler->GetOutput();
	}

	void resizeImage(float factor) {
		resizer = ShrinkerType::New();
		resizer->ChangeSpacingOn();
		resizer->SetInput( originalImage );
		ShrinkerType::SpacingType spacings3D = originalImage->GetSpacing();
		for(int i=0; i<3; i++) {
			spacings3D[i] = spacings3D[i]*factor;
		}
		resizer->SetOutputSpacing( spacings3D );
		resizer->Update();
		originalImage = resizer->GetOutput();
	}

	void buildOriginalMaskVolume() {
		// make new mask volume and make it all white
		MaskVolumeType::RegionType region;
		region.SetSize( originalImage->GetLargestPossibleRegion().GetSize() );

		originalMask = MaskVolumeType::New();
		originalMask->SetRegions( region );
		originalMask->CopyInformation( originalImage );
	  originalMask->Allocate();
    originalMask->FillBuffer( 255 );

		maskSpacer = MaskSpacerType::New();
		maskSpacer->ChangeSpacingOn();
		maskSpacer->SetOutputSpacing( originalImage->GetSpacing() );

		maskSpacer->SetInput( originalMask );
		maskSpacer->Update();
		originalMask = maskSpacer->GetOutput();

	  mask3D = MaskType3D::New();
		mask3D->SetImage( originalMask );
	}

	void initialiseFilters() {
		// resamplers
		transform = TransformType::New();
	  transform->SetIdentity();
		linearInterpolator = LinearInterpolatorType::New();
		nearestNeighborInterpolator = NearestNeighborInterpolatorType::New();
		resampler = ResamplerType::New();
    resampler->SetInput( originalImage );
		resampler->SetInterpolator( linearInterpolator );
		resampler->SetOutputSpacing( resamplerSpacing );
		resampler->SetSize( resamplerSize );
		resampler->SetTransform( transform );
		resampler->SetDefaultPixelValue( 127 );
		maskResampler = MaskResamplerType::New();
		maskResampler->SetInput( originalMask );
		maskResampler->SetInterpolator( nearestNeighborInterpolator );
		maskResampler->SetOutputSpacing( resamplerSpacing );
		maskResampler->SetSize( resamplerSize );
		maskResampler->SetTransform( transform );

		// extract image filters
    sliceExtractor = SliceExtractorType::New();
    sliceExtractor->SetInput( resampler->GetOutput() );
		maskSliceExtractor = MaskSliceExtractorType::New();
    maskSliceExtractor->SetInput( maskResampler->GetOutput() );
	}

	void buildSlices() {
	  // set up extractor
    VolumeType::SizeType size = resamplerSize;
    size[2] = 0;

    VolumeType::IndexType sliceIndex = {{0, 0, 0}};

    VolumeType::RegionType sliceRegion;
    sliceRegion.SetSize( size );
    sliceRegion.SetIndex( sliceIndex );

    sliceExtractor->SetExtractionRegion( sliceRegion );

    slices.clear();

    for(unsigned int i=0; i<resamplerSize[2]; i++) {
      // Set the z-coordinate of the slice to be extracted
      sliceIndex[2] = i;

      // add output to slices vector
      // sliceExtractor->Update();
      slices.push_back( sliceExtractor->GetOutput() );
      slices.back()->DisconnectPipeline();
    }

	}

	void buildMaskSlices() {
	  // set up extractor
    VolumeType::SizeType size = resamplerSize;
    size[2] = 0;

    VolumeType::IndexType sliceIndex = {{0, 0, 0}};

    VolumeType::RegionType sliceRegion;
    sliceRegion.SetSize( size );
    sliceRegion.SetIndex( sliceIndex );

    maskSliceExtractor->SetExtractionRegion( sliceRegion );

    maskSlices.clear();

    for(unsigned int i=0; i<resamplerSize[2]; i++) {
      // Set the z-coordinate of the slice to be extracted
      sliceIndex[2] = i;

      // add output to slices vector
      // maskSliceExtractor->Update();
      maskSlices.push_back( maskSliceExtractor->GetOutput() );
      maskSlices.back()->DisconnectPipeline();
    }

	}

	void SetTransformParameters(TransformType::Pointer inputTransform) {
    transform->SetParameters( inputTransform->GetParameters() );
    transform->SetFixedParameters( inputTransform->GetFixedParameters() );
	}

	VolumeType::Pointer GetVolume() {
		return originalImage;
	}

	MaskVolumeType::Pointer GetMaskVolume() {
		return originalMask;
	}

	MaskType3D::Pointer GetMask3D() {
		return mask3D;
	}

	VolumeType::Pointer GetResampledVolume() {
    resampler->Update();
    return resampler->GetOutput();
	}

	MaskVolumeType::Pointer GetResampledMaskVolume() {
    maskResampler->Update();
    return maskResampler->GetOutput();
	}

protected:
};
#endif
<commit_msg>Changed MRI volume linear interpolator to nearest neighbour.<commit_after>// This object encapsulates the 3D MRI data.
// Its job is to initialise the data,
//  take transform parameters,
// then provide slices and associated masks.

#ifndef MRI_HPP_
#define MRI_HPP_

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkResampleImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkChangeInformationImageFilter.h"
#include "itkImageMaskSpatialObject.h"
#include "itkImageRegionIterator.h"
#include "itkExtractImageFilter.h"

class MRI {
public:
	// unsigned char is native type, but multires can't handle unsigned types
  // typedef unsigned char PixelType;
  typedef short PixelType;
  typedef itk::Image< PixelType, 2 > SliceType;
	typedef itk::Image< unsigned char, 2 > MaskSliceType;
  typedef itk::Image< PixelType, 3 > VolumeType;
	typedef itk::Image< unsigned char, 3 > MaskVolumeType;
	typedef vector< SliceType::Pointer > SliceVectorType;
	typedef vector< MaskSliceType::Pointer > MaskSliceVectorType;
  typedef itk::ImageFileReader< VolumeType > ReaderType;
	typedef itk::RescaleIntensityImageFilter< VolumeType, VolumeType > RescaleIntensityFilterType;
	typedef itk::ChangeInformationImageFilter< VolumeType > ShrinkerType;
	typedef itk::ChangeInformationImageFilter< MaskVolumeType > MaskSpacerType;
	typedef itk::VersorRigid3DTransform< double > TransformType;
	typedef TransformType::ParametersType ParametersType;
  // typedef itk::LinearInterpolateImageFunction< VolumeType, double > VolumeInterpolatorType;
  typedef itk::NearestNeighborInterpolateImageFunction< VolumeType, double > VolumeInterpolatorType;
  typedef itk::NearestNeighborInterpolateImageFunction< MaskVolumeType, double > MaskVolumeInterpolatorType;
  typedef itk::ResampleImageFilter< VolumeType, VolumeType > ResamplerType;
  typedef itk::ResampleImageFilter< MaskVolumeType, MaskVolumeType > MaskResamplerType;
  typedef itk::ExtractImageFilter< VolumeType, SliceType > SliceExtractorType;
  typedef itk::ExtractImageFilter< MaskVolumeType, MaskSliceType > MaskSliceExtractorType;
  typedef itk::ImageRegionIterator< MaskVolumeType > IteratorType;
  typedef itk::ImageMaskSpatialObject< 3 > MaskType3D;
  typedef itk::ImageMaskSpatialObject< 2 > MaskType2D;
	typedef vector< MaskType2D::Pointer > MaskVectorType2D;

	VolumeType::Pointer originalImage;
	MaskVolumeType::Pointer originalMask;
  SliceVectorType slices;
  MaskSliceVectorType maskSlices;
	MaskType3D::Pointer mask3D;
  MaskVectorType2D masks2D;
  TransformType::Pointer transform;
  VolumeInterpolatorType::Pointer volumeInterpolator;
	MaskVolumeInterpolatorType::Pointer maskVolumeInterpolator;
	RescaleIntensityFilterType::Pointer intensityRescaler;
	ShrinkerType::Pointer resizer;
	MaskSpacerType::Pointer maskSpacer;
  ResamplerType::Pointer resampler;
  VolumeType::SpacingType resamplerSpacing;
  VolumeType::SizeType resamplerSize;
  MaskResamplerType::Pointer maskResampler;
  SliceExtractorType::Pointer sliceExtractor;
  MaskSliceExtractorType::Pointer maskSliceExtractor;

	MRI(char const *inputFileName, VolumeType::SpacingType spacing, VolumeType::SizeType size, double initialResizeFactor):
	  resamplerSpacing(spacing),
	  resamplerSize(size) {
		readFile(inputFileName);
		rescaleIntensity();
		resizeImage(initialResizeFactor);
		buildOriginalMaskVolume();
    initialiseFilters();
    buildSlices();
    buildMaskSlices();
	}

	void readFile(char const *inputFileName) {
	  ReaderType::Pointer volumeReader = ReaderType::New();
		volumeReader->SetFileName( inputFileName );
    volumeReader->Update();
		originalImage = volumeReader->GetOutput();
	}

	void rescaleIntensity() {
		intensityRescaler = RescaleIntensityFilterType::New();
		intensityRescaler->SetOutputMinimum( 0 );
		intensityRescaler->SetOutputMaximum( 255 );
		intensityRescaler->SetInput( originalImage );
		intensityRescaler->Update();
		originalImage = intensityRescaler->GetOutput();
	}

	void resizeImage(float factor) {
		resizer = ShrinkerType::New();
		resizer->ChangeSpacingOn();
		resizer->SetInput( originalImage );
		ShrinkerType::SpacingType spacings3D = originalImage->GetSpacing();
		for(int i=0; i<3; i++) {
			spacings3D[i] = spacings3D[i]*factor;
		}
		resizer->SetOutputSpacing( spacings3D );
		resizer->Update();
		originalImage = resizer->GetOutput();
	}

	void buildOriginalMaskVolume() {
		// make new mask volume and make it all white
		MaskVolumeType::RegionType region;
		region.SetSize( originalImage->GetLargestPossibleRegion().GetSize() );

		originalMask = MaskVolumeType::New();
		originalMask->SetRegions( region );
		originalMask->CopyInformation( originalImage );
	  originalMask->Allocate();
    originalMask->FillBuffer( 255 );

		maskSpacer = MaskSpacerType::New();
		maskSpacer->ChangeSpacingOn();
		maskSpacer->SetOutputSpacing( originalImage->GetSpacing() );

		maskSpacer->SetInput( originalMask );
		maskSpacer->Update();
		originalMask = maskSpacer->GetOutput();

	  mask3D = MaskType3D::New();
		mask3D->SetImage( originalMask );
	}

	void initialiseFilters() {
		// resamplers
		transform = TransformType::New();
	  transform->SetIdentity();
    volumeInterpolator = VolumeInterpolatorType::New();
		maskVolumeInterpolator = MaskVolumeInterpolatorType::New();
		resampler = ResamplerType::New();
    resampler->SetInput( originalImage );
		resampler->SetInterpolator( volumeInterpolator );
		resampler->SetOutputSpacing( resamplerSpacing );
		resampler->SetSize( resamplerSize );
		resampler->SetTransform( transform );
		resampler->SetDefaultPixelValue( 127 );
		maskResampler = MaskResamplerType::New();
		maskResampler->SetInput( originalMask );
		maskResampler->SetInterpolator( maskVolumeInterpolator );
		maskResampler->SetOutputSpacing( resamplerSpacing );
		maskResampler->SetSize( resamplerSize );
		maskResampler->SetTransform( transform );

		// extract image filters
    sliceExtractor = SliceExtractorType::New();
    sliceExtractor->SetInput( resampler->GetOutput() );
		maskSliceExtractor = MaskSliceExtractorType::New();
    maskSliceExtractor->SetInput( maskResampler->GetOutput() );
	}

	void buildSlices() {
	  // set up extractor
    VolumeType::SizeType size = resamplerSize;
    size[2] = 0;

    VolumeType::IndexType sliceIndex = {{0, 0, 0}};

    VolumeType::RegionType sliceRegion;
    sliceRegion.SetSize( size );
    sliceRegion.SetIndex( sliceIndex );

    sliceExtractor->SetExtractionRegion( sliceRegion );

    slices.clear();

    for(unsigned int i=0; i<resamplerSize[2]; i++) {
      // Set the z-coordinate of the slice to be extracted
      sliceIndex[2] = i;

      // add output to slices vector
      // sliceExtractor->Update();
      slices.push_back( sliceExtractor->GetOutput() );
      slices.back()->DisconnectPipeline();
    }

	}

	void buildMaskSlices() {
	  // set up extractor
    VolumeType::SizeType size = resamplerSize;
    size[2] = 0;

    VolumeType::IndexType sliceIndex = {{0, 0, 0}};

    VolumeType::RegionType sliceRegion;
    sliceRegion.SetSize( size );
    sliceRegion.SetIndex( sliceIndex );

    maskSliceExtractor->SetExtractionRegion( sliceRegion );

    maskSlices.clear();

    for(unsigned int i=0; i<resamplerSize[2]; i++) {
      // Set the z-coordinate of the slice to be extracted
      sliceIndex[2] = i;

      // add output to slices vector
      // maskSliceExtractor->Update();
      maskSlices.push_back( maskSliceExtractor->GetOutput() );
      maskSlices.back()->DisconnectPipeline();
    }

	}

	void SetTransformParameters(TransformType::Pointer inputTransform) {
    transform->SetParameters( inputTransform->GetParameters() );
    transform->SetFixedParameters( inputTransform->GetFixedParameters() );
	}

	VolumeType::Pointer GetVolume() {
		return originalImage;
	}

	MaskVolumeType::Pointer GetMaskVolume() {
		return originalMask;
	}

	MaskType3D::Pointer GetMask3D() {
		return mask3D;
	}

	VolumeType::Pointer GetResampledVolume() {
    resampler->Update();
    return resampler->GetOutput();
	}

	MaskVolumeType::Pointer GetResampledMaskVolume() {
    maskResampler->Update();
    return maskResampler->GetOutput();
	}

protected:
};
#endif
<|endoftext|>


<commit_before>#include "persistenceDiagrams/PersistenceDiagram.hh"
#include "persistenceDiagrams/Norms.hh"

#include "persistentHomology/Calculation.hh"

#include "topology/io/PLY.hh"

#include "utilities/Timer.hh"

#include <iostream>

using DataType          = double;
using VertexType        = unsigned;
using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

int main( int argc, char** argv )
{
  std::string filename;
  std::string property = "quality";

  if( argc == 1 )
    return -1;

  if( argc >= 2 )
    filename = argv[1];

  if( argc >= 3 )
    property = argv[2];

  aleph::topology::io::PLYReader plyReader;
  plyReader.setDataProperty( property );

  SimplicialComplex K;
  plyReader( filename, K );

  // TODO:
  //   - Expansion (higher-dimensional simplices)
  //   - Different filtrations (superlevel, sublevel)

  std::cerr << "* Loaded simplicial complex with " << K.size() << " simplices\n";

  aleph::utilities::Timer timer;

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  std::cerr << "* Calculated " << diagrams.size() << " persistence diagrams in " << timer.elapsed_s() << "s\n";

  for( auto&& D : diagrams )
  {
    D.removeDiagonal();
    std::cout << D << "\n";
  }

  for( auto&& D : diagrams )
  {
    std::cerr << "* Total degree-1 persistence: " << aleph::totalPersistence( D, 1.0 ) << "\n"
              << "* Total degree-2 persistence: " << aleph::totalPersistence( D, 2.0 ) << "\n"
              << "* 1-norm:                     " << aleph::pNorm( D, 1.0 ) << "\n"
              << "* 2-norm:                     " << aleph::pNorm( D, 2.0 ) << "\n";
  }
}
<commit_msg>Started documenting PLY example<commit_after>/*
  This is an example file shipped by 'Aleph - A Library for Exploring
  Persistent Homology'.

  This example demonstrates how to load a mesh in PLY format from
  a file, convert it into a simplicial complex, and calculate its
  persistent homology. The Weights for the simplicial complex are
  taken from a user-specified property within the PLY file.

  Demonstrated classes:

    - aleph::PersistenceDiagram
    - aleph::topology::Simplex
    - aleph::topology::SimplicialComplex
    - aleph::topology::io::PLYReader
    - aleph::utilities::Timer

  Demonstrated functions:

    - aleph::calculatePersistenceDiagrams
    - aleph::pNorm
    - aleph::totalPersistence
    - Persistence diagram pruning

  Original author: Bastian Rieck
*/

#include "persistenceDiagrams/PersistenceDiagram.hh"
#include "persistenceDiagrams/Norms.hh"

#include "persistentHomology/Calculation.hh"

#include "topology/io/PLY.hh"

#include "utilities/Timer.hh"

#include <iostream>
#include <vector>

int main( int argc, char** argv )
{
  std::string filename;
  std::string property = "quality";

  if( argc == 1 )
  {
    // TODO: usage
    return -1;
  }

  if( argc >= 2 )
    filename = argv[1];

  if( argc >= 3 )
    property = argv[2];

  // Loading -----------------------------------------------------------

  // We first declare the data types we want to convert the file to so
  // that the PLY reader class knows the desired type of complex. Note
  // that the `Simplex` and `SimplicialComplex` type are declared just
  // for reasons of convenience.
  using DataType          = double;
  using VertexType        = unsigned;
  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

  // Declares the reader for loading a PLY file. At present, the loading
  // of binary files is not yet supported (even though some code exists)
  // and the reader only handles ASCII files properly.
  //
  // Note that we set a 'data property'. This specifies the attribute of
  // every vertex that is used to assign the data values of simplices in
  // the simplicial complex. The property defaults to 'z', i.e. the last
  // coordinate of every vertex. In this example, we permit users to use
  // another property.
  //
  // See https://en.wikipedia.org/wiki/PLY_(file_format) for information
  // about the PLY format.
  aleph::topology::io::PLYReader plyReader;
  plyReader.setDataProperty( property );

  SimplicialComplex K;
  plyReader( filename, K );

  std::cerr << "* Loaded simplicial complex with " << K.size() << " simplices\n";

  // Persistent homology -----------------------------------------------
  //
  // At present, only the mesh connectivity is used to calculate
  // persistent homology.
  //
  // Note that we do not have to sort K, the simplicial complex,
  // prior to the calculations. By default, the PLY reader sorts
  // the complex from small weights to large weights.
  //
  // TODO:
  //   - Expansion (higher-dimensional simplices)
  //   - Different filtrations (superlevel, sublevel)

  // This small utility class permits measuring the time of certain
  // operations. Internally, it makes use of `std::chrono` in order
  // to permit a sufficiently fine resolution.
  aleph::utilities::Timer timer;

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  std::cerr << "* Calculated " << diagrams.size() << " persistence diagrams in " << timer.elapsed_s() << "s\n";

  for( auto&& D : diagrams )
  {
    // Removes all features with zero persistence from the diagram in
    // order to simplify it.
    D.removeDiagonal();

    // This results in a tabular output of all points in the diagram;
    // it is ideally suited for further analysis in 'gnuplot'. Notice
    // that the two new lines can be used to automatically detect the
    // next dimension of the diagram.
    std::cout << D << "\n\n";
  }

  for( auto&& D : diagrams )
  {
    // Displays some statistics about the persistence diagrams. The
    // total persistence (with some power $p$) refers to the sum of
    // all persistence values, while the $p$-norm is merely a power
    // of the total persistence value.
    //
    // Both norms are useful for determining the amount of activity
    // within a data set.
    std::cerr << "* Total degree-1 persistence: " << aleph::totalPersistence( D, 1.0 ) << "\n"
              << "* Total degree-2 persistence: " << aleph::totalPersistence( D, 2.0 ) << "\n"
              << "* 1-norm:                     " << aleph::pNorm( D, 1.0 ) << "\n"
              << "* 2-norm:                     " << aleph::pNorm( D, 2.0 ) << "\n";
  }
}
<|endoftext|>


<commit_before>//
//  Board.cpp
//  tetris
//
//  Created by Xhacker Liu on 2/14/14.
//  Copyright (c) 2014 Xhacker. All rights reserved.
//

#include "Board.h"
#include "constants.h"
#include "include/Angel.h"
#include <iostream>

using namespace std;

bool Board::has_collision(bool tetro_blocks[4][4], int steps, int cur_x)
{
    int left_most = INFINITY;
    int right_most = -INFINITY;
    int bottom_most = -INFINITY;
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x]) {
                if (x < left_most) {
                    left_most = x;
                }
                if (x > right_most) {
                    right_most = x;
                }
                if (y > bottom_most) {
                    bottom_most = y;
                }
            }
        }
    }

    // Check side border, left_most and right_most are between 0~3
    if (cur_x + left_most < 0) {
        return true;
    }
    if (cur_x + right_most > 9) {
        return true;
    }

    // Check bottom border
    if (steps + bottom_most >= 20) {
        return true;
    }

    // Check collision
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x] && blocks[steps + y][cur_x + x]) {
                return true;
            }
        }
    }

    return false;
}

void Board::add_blocks(bool tetro_blocks[4][4], int steps, int cur_x)
{
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x] && steps + y < 20 && cur_x + x < 10) {
                if (blocks[steps + y][cur_x + x] == 0) {
                    num_of_points += 4;
                }
                blocks[steps + y][cur_x + x] = 1;
            }
        }
    }
}

void Board::write_buffer()
{
    int current = 0;
    for (int i = 0; i < 20; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (blocks[i][j]) {
                cout << i << ", " << j << ", " << num_of_points << endl;
                vec2 points[4];
                points[0] = vec2(-W + (j    ) * BLOCK_W, H - (i + 1) * BLOCK_H);
                points[1] = vec2(-W + (j + 1) * BLOCK_W, H - (i + 1) * BLOCK_H);
                points[2] = vec2(-W + (j    ) * BLOCK_W, H - i * BLOCK_H);
                points[3] = vec2(-W + (j + 1) * BLOCK_W, H - i * BLOCK_H);
                glBufferSubData(GL_ARRAY_BUFFER, (kBeginBoardPoints + 4 * current) * sizeof(vec2), sizeof(points), points);

                current += 1;
            }
        }
    }
}
<commit_msg>Clear full row.<commit_after>//
//  Board.cpp
//  tetris
//
//  Created by Xhacker Liu on 2/14/14.
//  Copyright (c) 2014 Xhacker. All rights reserved.
//

#include "Board.h"
#include "constants.h"
#include "include/Angel.h"
#include <iostream>

using namespace std;

bool Board::has_collision(bool tetro_blocks[4][4], int steps, int cur_x)
{
    int left_most = INFINITY;
    int right_most = -INFINITY;
    int bottom_most = -INFINITY;
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x]) {
                if (x < left_most) {
                    left_most = x;
                }
                if (x > right_most) {
                    right_most = x;
                }
                if (y > bottom_most) {
                    bottom_most = y;
                }
            }
        }
    }

    // Check side border, left_most and right_most are between 0~3
    if (cur_x + left_most < 0) {
        return true;
    }
    if (cur_x + right_most > 9) {
        return true;
    }

    // Check bottom border
    if (steps + bottom_most >= 20) {
        return true;
    }

    // Check collision
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x] && blocks[steps + y][cur_x + x]) {
                return true;
            }
        }
    }

    return false;
}

void Board::add_blocks(bool tetro_blocks[4][4], int steps, int cur_x)
{
    for (int y = 0; y < 4; ++y) {
        for (int x = 0; x < 4; ++x) {
            if (tetro_blocks[y][x] && steps + y < 20 && cur_x + x < 10) {
                if (!blocks[steps + y][cur_x + x]) {
                    num_of_points += 4;
                }
                blocks[steps + y][cur_x + x] = 1;
            }
        }
    }

    // Check full row
    for (int y = 0; y < 20; ++y) {
        bool full = true;
        for (int x = 0; x < 10; ++x) {
            if (!blocks[y][x]) {
                full = false;
                break;
            }
        }

        if (full) {
            memcpy(blocks[1], blocks[0], y * 10 * sizeof(bool));
            memset(blocks[0], 0, 10 * sizeof(bool));
            num_of_points -= 4 * 10;
        }
    }
}

void Board::write_buffer()
{
    int current = 0;
    for (int i = 0; i < 20; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (blocks[i][j]) {
                vec2 points[4];
                points[0] = vec2(-W + (j    ) * BLOCK_W, H - (i + 1) * BLOCK_H);
                points[1] = vec2(-W + (j + 1) * BLOCK_W, H - (i + 1) * BLOCK_H);
                points[2] = vec2(-W + (j    ) * BLOCK_W, H - i * BLOCK_H);
                points[3] = vec2(-W + (j + 1) * BLOCK_W, H - i * BLOCK_H);
                glBufferSubData(GL_ARRAY_BUFFER, (kBeginBoardPoints + 4 * current) * sizeof(vec2), sizeof(points), points);

                current += 1;
            }
        }
    }
}
<|endoftext|>


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

#include <string>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include "picoopt.h"

using namespace std;

typedef unsigned char byte;

const char* usage[] = {
  "",
  "  VuXprog is a serial programmer for universal and extensible AVR",
  "    serial bootloader VuXboot.",
  "  This software is not affiliated with Atmel in any way.",
  "",
  "  Actions|abbreviations:",
  "    flash_read|fr <filename>",
  "    flash_write|fw <filename>",
  "    eeprom_read|er <filename>",
  "    eeprom_write|ew <filename>",
  "    reset|r",
  "",
  "  Options:",
  "    -s PORT\tset serial port device; default is /dev/ttyUSB0",
  "    -f FORMAT\tset file format; FORMAT may be ihex (default) or binary",
  "    -i SEQ\tstart bootloader by sending SEQ to port",
  "    -F\t\tdo things which sane human wouldn't",
  ""
};

namespace storage {
  enum format {
    ihex,
    binary
  };
}

class error: public exception {
public:
  error(string message) : _message(message) {}
  string message() { return _message; }
  ~error() throw() { }

private:
  string _message;
};

class io_error: public error {
public:
  io_error(string message) : error(message) {}
};

class feature_error: public error {
public:
  feature_error(string message) : error(message) {}
};

class hardware_error: public error {
public:
  hardware_error(string message) : error(message) {}
};

class protocol_error: public error {
public:
  protocol_error(string info, string node="") : error(make_message(info, node)) {}
  ~protocol_error() throw() {}

private:
  static string make_message(string info, string node) {
    string message = info;
    if(node != "")
      message += ": `" + node + "'";
    return message;
  }
};

class vuxboot {
public:
  vuxboot(string filename, unsigned baud = 0) {
    _fd = open(filename.c_str(), O_RDWR | O_NONBLOCK);
    if(!_fd) throw new io_error("cannot open port");

    // TODO: set baud rate
  }

  ~vuxboot() {
    close(_fd);
  }

  void identify() {
    write("s");

    string signature = read(3);
    if(signature != "VuX")
      throw new protocol_error("wrong signature", signature);

    string s_type = read(1);
    if(s_type != "f" && s_type != "e")
      throw new protocol_error("wrong type", s_type);

    _has_eeprom = (s_type == "e");
    if(_has_eeprom) {
      string s_eesize = read(1);
      _eeprom_bytes = 1 << s_eesize[0];
      s_type += s_eesize;
    }

    string s_flash_sizes = read(3);
    _page_words = s_flash_sizes[0];
    _flash_pages = 1 << s_flash_sizes[1];
    _boot_pages = s_flash_sizes[2];

    string s_checksum = read(1);

    string concat = signature + s_type + s_flash_sizes;
    char checksum = 0;
    for(int i = 0; i < concat.length(); i++)
      checksum += concat[i];

    if(checksum != s_checksum[0])
      throw new protocol_error("bad checksum");
  }

  void describe() {
    cout << "Device capabilities:" << endl;
    if(_has_eeprom)
      cout << "  EEPROM: " << _eeprom_bytes << " bytes." << endl;
    cout << "  Page size: " << _page_words << " words." << endl;
    cout << "  Flash size: " << _flash_pages << " pages." << endl;
    cout << "  Reserved area: " << _boot_pages << " pages (at end)." << endl;
  }

  string read_flash(unsigned page) {
    if(page > flash_pages())
      throw new feature_error("flash page address too big");

    string req = "r";
    req += char(page & 0xff);
    req += char(page >> 8);
    write(req);

    return read(_page_words * 2);
  }

  void write_flash(unsigned page, string words) {
    if(words.length() != _page_words * 2)
      throw new feature_error("flash page size mismatch");

    string req = "w", status;
    req += words;
    req += char(page & 0xff);
    req += char(page >> 8);
    write(req);

    status = read(1);
    if(status != ".")
      throw new hardware_error("cannot write flash");
  }

  string read_eeprom() {
    if(!_has_eeprom)
      throw new feature_error("no eeprom");

    write("R");
    return read(_eeprom_bytes);
  }

  void write_eeprom(unsigned address, byte b) {
    if(!_has_eeprom)
      throw new feature_error("no eeprom");
    if(address > _eeprom_bytes)
      throw new feature_error("eeprom address too big");

    string req = "W";
    req += char(address & 0xff);
    req += char(address >> 8);
    req += char(b);
    write(req);

    string status = read(1);
    if(status != ".")
      throw new hardware_error("cannot write eeprom");
  }

  void reset() {
    write("q");
  }

  bool has_eeprom() {
    return _has_eeprom;
  }

  unsigned eeprom_bytes() {
    return _eeprom_bytes;
  }

  unsigned flash_pages() {
    return _flash_pages;
  }

  unsigned boot_pages() {
    return _boot_pages;
  }

  unsigned page_words() {
    return _page_words;
  }

private:
  string read(unsigned length, unsigned timeout=5) {
    char data[length];

    unsigned received = 0;
    while(received < length) {
      struct timeval to = {0};
      to.tv_sec = timeout;

      fd_set rfds, efds;
      FD_ZERO(&rfds);
      FD_SET(_fd, &rfds);

      FD_ZERO(&efds);
      FD_SET(_fd, &efds);

      int retval = select(FD_SETSIZE, &rfds, NULL, &efds, &to);
      if(retval == -1) {
        throw new io_error("cannot select()");
      } else if(retval == 0) {
        throw new io_error("read timeout");
      } else if(FD_ISSET(_fd, &efds)) {
        throw new io_error("i/o error");
      }

      retval = ::read(_fd, data + received, length);
      if(retval == -1) {
        throw new io_error("cannot read()");
      }

      received += retval;
    }

    return string(data, received);
  }

  void write(string data) {
    if(::write(_fd, data.c_str(), data.length()) != data.length()) {
      throw new io_error("cannot write()");
    }
  }

private:
  int _fd;

  bool _has_eeprom;
  unsigned _eeprom_bytes;
  unsigned _page_words, _flash_pages, _boot_pages;
};

string read_file(string filename, storage::format format) {
  ios::openmode flags = ios::ate;
  if(format == storage::binary)
    flags |= ios::binary;

  ifstream in(filename.c_str(), flags);
  if(!in)
    throw new io_error("cannot read from data file");

  unsigned size = (unsigned) in.tellg();
  in.seekg(0);

  char data[size];
  in.read(data, size);

  if(format == storage::binary) {
    return string(data, size);
  }
}

bool write_file(string filename, storage::format format, string data) {
  ios::openmode flags;
  if(format == storage::binary)
    flags = ios::binary;

  ofstream out(filename.c_str(), flags);
  if(!out)
    throw new io_error("cannot write to data file");

  if(format == storage::binary) {
    out << data;
  }
}

int main(int argc, char* argv[]) {
  picoopt::parser opts;
  opts.option('s', true);
  opts.option('f', true);
  opts.option('i', true);
  opts.option('F');

  if(!opts.parse(argc, argv) || opts.has('h') || !opts.valid() || (opts.args().size() != 2 &&
        (opts.args().size() != 1 || (opts.args()[0] != "r" && opts.args()[0] != "reset")))) {
    cout << "Usage: " << argv[0] << " <action> [argument] ..." << endl;
    for(int i = 0; i < sizeof(usage) / sizeof(usage[0]); i++)
        cout << usage[i] << endl;
    return 1;
  }

  bool force = opts.has('F');

  storage::format format = storage::ihex;
  if(opts.has('f')) {
    string new_format = opts.get('f');
    if(new_format == "ihex") {
      format = storage::ihex;
    } else if(new_format == "binary") {
      format = storage::binary;
    } else {
      cerr << "unknown storage format `" << new_format << "'!" << endl;
      return 1;
    }
  }

  string port = "/dev/ttyUSB0";
  if(opts.has('s'))
    port = opts.get('s');

  try {
    vuxboot bl(port);
    bl.identify();
    bl.describe();

    string action = opts.args()[0];
    if(action == "flash_read" || action == "fr") {
      string flash;

      cout << "Reading flash: " << flush;
      for(int page = 0; page < bl.flash_pages(); page++) {
        flash += bl.read_flash(page);
        if(page % 10 == 1)
          cout << "." << flush;
      }
      cout << endl;

      write_file(opts.args()[1], format, flash);
    } else if(action == "flash_write" || action == "fw") {
      string flash = read_file(opts.args()[1], format);

      unsigned page_bytes = bl.page_words() * 2;
      unsigned even_pages = flash.length() / page_bytes + (flash.length() % page_bytes > 0);
      flash.resize(even_pages * page_bytes, 0xff);

      if(even_pages > bl.flash_pages() - bl.boot_pages()) {
        cerr << "                         / ! \\      / ! \\       / ! \\" << endl;
        if(!force) {
          cerr << "* Image is " << even_pages << " pages long; writing it will "
               << "overwrite the bootloader" << endl << "* at pages "
               << bl.flash_pages() - bl.boot_pages() << "-" << bl.flash_pages() - 1
               << ". "
               << "Pass the -F flag if you really know what are you doing." << endl
               << "* Probably you will just overwrite first page of bootloader "
               << "and then everything" << endl
               << "* will fail, leaving you with a nice brick." << endl;
          return 1;
        } else if(force) {
          cerr << "* Shooting myself in the leg." << endl;
        }
      }

      cout << "Writing flash: " << flush;

      unsigned changed = 0;
      for(int page = 0; page < even_pages; page++) {
        string new_page = flash.substr(page * page_bytes, page_bytes);
        if(new_page != string(page_bytes, (char) 0xff)) {
          string old_page = bl.read_flash(page);
          if(old_page != new_page) {
            bl.write_flash(page, new_page);
            if(changed++ % 10 == 0)
              cout << "." << flush;
            if(bl.read_flash(page) != new_page) {
              cerr << "verification failed!" << endl;
              return 1;
            }
          }
        }
      }

      cout << " " << changed << " pages." << endl;
    } else if(action == "eeprom_read" || action == "er") {
      write_file(opts.args()[1], format, bl.read_eeprom());
    } else if(action == "eeprom_write" || action == "ew") {
      string old_eeprom = bl.read_eeprom();
      string new_eeprom = read_file(opts.args()[1], format);

      if(new_eeprom.length() > old_eeprom.length()) {
        cerr << "eeprom image is too big!" << endl;
        return 1;
      }

      new_eeprom.resize(old_eeprom.length(), 0xff);

      cout << "Writing eeprom: " << flush;

      unsigned changed = 0;
      for(int i = 0; i < new_eeprom.length(); i++) {
        if(old_eeprom[i] != new_eeprom[i]) {
          bl.write_eeprom(i, new_eeprom[i]);
          if(changed++ % 10 == 0)
            cout << "." << flush;
        }
      }

      cout << " " << changed << " bytes." << endl;

      if(bl.read_eeprom() != new_eeprom) {
        cerr << "verification failed!" << endl;
        return 1;
      }
    } else if(action == "reset" || action == "r") {
      cout << "Resetting device..." << endl;
      bl.reset();
    } else {
      cerr << "unknown action!" << endl;
      return 1;
    }
  } catch(io_error *e) {
    cerr << "i/o error: " << e->message() << endl;
    return 1;
  } catch(protocol_error *e) {
    cerr << "protocol error: " << e->message() << endl;
    return 1;
  } catch(hardware_error *e) {
    cerr << "hardware error: " << e->message() << endl;
    return 1;
  }

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

#include <string>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include "picoopt.h"

using namespace std;

typedef unsigned char byte;

const char* usage[] = {
  "",
  "  VuXprog is a serial programmer for universal and extensible AVR",
  "    serial bootloader VuXboot.",
  "  This software is not affiliated with Atmel in any way.",
  "",
  "  Actions|abbreviations:",
  "    flash_read|fr <filename>",
  "    flash_write|fw <filename>",
  "    eeprom_read|er <filename>",
  "    eeprom_write|ew <filename>",
  "    reset|r",
  "",
  "  Options:",
  "    -s PORT\tset serial port device; default is /dev/ttyUSB0",
  "    -f FORMAT\tset file format; FORMAT may be ihex (default) or binary",
  "    -i SEQ\tstart bootloader by sending SEQ to port",
  "    -F\t\tdo things which sane human wouldn't",
  ""
};

namespace storage {
  enum format {
    ihex,
    binary
  };
}

class error: public exception {
public:
  error(string message) : _message(message) {}
  string message() { return _message; }
  ~error() throw() { }

private:
  string _message;
};

class io_error: public error {
public:
  io_error(string message) : error(message) {}
};

class feature_error: public error {
public:
  feature_error(string message) : error(message) {}
};

class hardware_error: public error {
public:
  hardware_error(string message) : error(message) {}
};

class input_error: public error {
public:
  input_error(string message) : error(message) {}
};

class protocol_error: public error {
public:
  protocol_error(string info, string node="") : error(make_message(info, node)) {}
  ~protocol_error() throw() {}

private:
  static string make_message(string info, string node) {
    string message = info;
    if(node != "")
      message += ": `" + node + "'";
    return message;
  }
};

class vuxboot {
public:
  vuxboot(string filename, unsigned baud = 0) {
    _fd = open(filename.c_str(), O_RDWR | O_NONBLOCK);
    if(!_fd) throw new io_error("cannot open port");

    // TODO: set baud rate
  }

  ~vuxboot() {
    close(_fd);
  }

  void identify() {
    write("s");

    string signature = read(3);
    if(signature != "VuX")
      throw new protocol_error("wrong signature", signature);

    string s_type = read(1);
    if(s_type != "f" && s_type != "e")
      throw new protocol_error("wrong type", s_type);

    _has_eeprom = (s_type == "e");
    if(_has_eeprom) {
      string s_eesize = read(1);
      _eeprom_bytes = 1 << s_eesize[0];
      s_type += s_eesize;
    }

    string s_flash_sizes = read(3);
    _page_words = s_flash_sizes[0];
    _flash_pages = 1 << s_flash_sizes[1];
    _boot_pages = s_flash_sizes[2];

    string s_checksum = read(1);

    string concat = signature + s_type + s_flash_sizes;
    char checksum = 0;
    for(int i = 0; i < concat.length(); i++)
      checksum += concat[i];

    if(checksum != s_checksum[0])
      throw new protocol_error("bad checksum");
  }

  void describe() {
    cout << "Device capabilities:" << endl;
    if(_has_eeprom)
      cout << "  EEPROM: " << _eeprom_bytes << " bytes." << endl;
    cout << "  Page size: " << _page_words << " words." << endl;
    cout << "  Flash size: " << _flash_pages << " pages." << endl;
    cout << "  Reserved area: " << _boot_pages << " pages (at end)." << endl;
  }

  string read_flash(unsigned page) {
    if(page > flash_pages())
      throw new input_error("flash page address too big");

    string req = "r";
    req += char(page & 0xff);
    req += char(page >> 8);
    write(req);

    return read(_page_words * 2);
  }

  void write_flash(unsigned page, string words) {
    if(words.length() != _page_words * 2)
      throw new error("flash page size mismatch");

    string req = "w", status;
    req += words;
    req += char(page & 0xff);
    req += char(page >> 8);
    write(req);

    status = read(1);
    if(status != ".")
      throw new hardware_error("cannot write flash");
  }

  string read_eeprom() {
    if(!_has_eeprom)
      throw new feature_error("no eeprom");

    write("R");
    return read(_eeprom_bytes);
  }

  void write_eeprom(unsigned address, byte b) {
    if(!_has_eeprom)
      throw new feature_error("no eeprom");
    if(address > _eeprom_bytes)
      throw new input_error("eeprom address too big");

    string req = "W";
    req += char(address & 0xff);
    req += char(address >> 8);
    req += char(b);
    write(req);

    string status = read(1);
    if(status != ".")
      throw new hardware_error("cannot write eeprom");
  }

  void reset() {
    write("q");
  }

  bool has_eeprom() {
    return _has_eeprom;
  }

  unsigned eeprom_bytes() {
    return _eeprom_bytes;
  }

  unsigned flash_pages() {
    return _flash_pages;
  }

  unsigned boot_pages() {
    return _boot_pages;
  }

  unsigned page_words() {
    return _page_words;
  }

private:
  string read(unsigned length, unsigned timeout=5) {
    char data[length];

    unsigned received = 0;
    while(received < length) {
      struct timeval to = {0};
      to.tv_sec = timeout;

      fd_set rfds, efds;
      FD_ZERO(&rfds);
      FD_SET(_fd, &rfds);

      FD_ZERO(&efds);
      FD_SET(_fd, &efds);

      int retval = select(FD_SETSIZE, &rfds, NULL, &efds, &to);
      if(retval == -1) {
        throw new io_error("cannot select()");
      } else if(retval == 0) {
        throw new io_error("read timeout");
      } else if(FD_ISSET(_fd, &efds)) {
        throw new io_error("i/o error");
      }

      retval = ::read(_fd, data + received, length);
      if(retval == -1) {
        throw new io_error("cannot read()");
      }

      received += retval;
    }

    return string(data, received);
  }

  void write(string data) {
    if(::write(_fd, data.c_str(), data.length()) != data.length()) {
      throw new io_error("cannot write()");
    }
  }

private:
  int _fd;

  bool _has_eeprom;
  unsigned _eeprom_bytes;
  unsigned _page_words, _flash_pages, _boot_pages;
};

string read_file(string filename, storage::format format) {
  ios::openmode flags = ios::ate;
  if(format == storage::binary)
    flags |= ios::binary;

  ifstream in(filename.c_str(), flags);
  if(!in)
    throw new io_error("cannot read from data file");

  unsigned size = (unsigned) in.tellg();
  in.seekg(0);

  char data[size];
  in.read(data, size);

  if(format == storage::binary) {
    return string(data, size);
  }
}

bool write_file(string filename, storage::format format, string data) {
  ios::openmode flags;
  if(format == storage::binary)
    flags = ios::binary;

  ofstream out(filename.c_str(), flags);
  if(!out)
    throw new io_error("cannot write to data file");

  if(format == storage::binary) {
    out << data;
  }
}

int main(int argc, char* argv[]) {
  picoopt::parser opts;
  opts.option('s', true);
  opts.option('f', true);
  opts.option('i', true);
  opts.option('F');

  if(!opts.parse(argc, argv) || opts.has('h') || !opts.valid() || (opts.args().size() != 2 &&
        (opts.args().size() != 1 || (opts.args()[0] != "r" && opts.args()[0] != "reset")))) {
    cout << "Usage: " << argv[0] << " <action> [argument] ..." << endl;
    for(int i = 0; i < sizeof(usage) / sizeof(usage[0]); i++)
        cout << usage[i] << endl;
    return 1;
  }

  bool force = opts.has('F');

  storage::format format = storage::ihex;
  if(opts.has('f')) {
    string new_format = opts.get('f');
    if(new_format == "ihex") {
      format = storage::ihex;
    } else if(new_format == "binary") {
      format = storage::binary;
    } else {
      cerr << "unknown storage format `" << new_format << "'!" << endl;
      return 1;
    }
  }

  string port = "/dev/ttyUSB0";
  if(opts.has('s'))
    port = opts.get('s');

  try {
    vuxboot bl(port);
    bl.identify();
    bl.describe();

    string action = opts.args()[0];
    if(action == "flash_read" || action == "fr") {
      string flash;

      cout << "Reading flash: " << flush;
      for(int page = 0; page < bl.flash_pages(); page++) {
        flash += bl.read_flash(page);
        if(page % 10 == 1)
          cout << "." << flush;
      }
      cout << endl;

      write_file(opts.args()[1], format, flash);
    } else if(action == "flash_write" || action == "fw") {
      string flash = read_file(opts.args()[1], format);

      unsigned page_bytes = bl.page_words() * 2;
      unsigned even_pages = flash.length() / page_bytes + (flash.length() % page_bytes > 0);
      flash.resize(even_pages * page_bytes, 0xff);

      if(even_pages > bl.flash_pages() - bl.boot_pages()) {
        cerr << "                         / ! \\      / ! \\       / ! \\" << endl;
        if(!force) {
          cerr << "* Image is " << even_pages << " pages long; writing it will "
               << "overwrite the bootloader" << endl << "* at pages "
               << bl.flash_pages() - bl.boot_pages() << "-" << bl.flash_pages() - 1
               << ". "
               << "Pass the -F flag if you really know what are you doing." << endl
               << "* Probably you will just overwrite first page of bootloader "
               << "and then everything" << endl
               << "* will fail, leaving you with a nice brick." << endl;
          return 1;
        } else if(force) {
          cerr << "* Shooting myself in the leg." << endl;
        }
      }

      cout << "Writing flash: " << flush;

      unsigned changed = 0;
      for(int page = 0; page < even_pages; page++) {
        string new_page = flash.substr(page * page_bytes, page_bytes);
        if(new_page != string(page_bytes, (char) 0xff)) {
          string old_page = bl.read_flash(page);
          if(old_page != new_page) {
            bl.write_flash(page, new_page);
            if(changed++ % 10 == 0)
              cout << "." << flush;
            if(bl.read_flash(page) != new_page) {
              cerr << "verification failed!" << endl;
              return 1;
            }
          }
        }
      }

      cout << " " << changed << " pages." << endl;
    } else if(action == "eeprom_read" || action == "er") {
      write_file(opts.args()[1], format, bl.read_eeprom());
    } else if(action == "eeprom_write" || action == "ew") {
      string old_eeprom = bl.read_eeprom();
      string new_eeprom = read_file(opts.args()[1], format);

      if(new_eeprom.length() > old_eeprom.length()) {
        cerr << "eeprom image is too big!" << endl;
        return 1;
      }

      new_eeprom.resize(old_eeprom.length(), 0xff);

      cout << "Writing eeprom: " << flush;

      unsigned changed = 0;
      for(int i = 0; i < new_eeprom.length(); i++) {
        if(old_eeprom[i] != new_eeprom[i]) {
          bl.write_eeprom(i, new_eeprom[i]);
          if(changed++ % 10 == 0)
            cout << "." << flush;
        }
      }

      cout << " " << changed << " bytes." << endl;

      if(bl.read_eeprom() != new_eeprom) {
        cerr << "verification failed!" << endl;
        return 1;
      }
    } else if(action == "reset" || action == "r") {
      cout << "Resetting device..." << endl;
      bl.reset();
    } else {
      cerr << "unknown action!" << endl;
      return 1;
    }
  } catch(input_error *e) {
    cerr << "input error: " << e->message() << endl;
    return 1;
  } catch(io_error *e) {
    cerr << "i/o error: " << e->message() << endl;
    return 1;
  } catch(protocol_error *e) {
    cerr << "protocol error: " << e->message() << endl;
    return 1;
  } catch(hardware_error *e) {
    cerr << "hardware error: " << e->message() << endl;
    return 1;
  } catch(error *e) {
    cerr << "internal error: " << e->message() << endl;
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Express RefinementState as text rather than numeric codes when printing Elem info<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: globals.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: jl $ $Date: 2001-08-14 13:57:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANTS_HPP_
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
#endif

#include "globals.hxx"

//--> TRA
#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

// used as shortcut when drag-source and drop-target are the same
::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > g_XTransferable;

//<-- TRA

using namespace com::sun::star::datatransfer::dnd::DNDConstants;

sal_Int8 dndOleKeysToAction( DWORD grfKeyState, sal_Int8 nSourceActions)
{
    sal_Int8 ret= 0;

    // no MK_ALT, MK_CONTROL, MK_SHIFT
    if( !(grfKeyState & MK_CONTROL) &&
        !(grfKeyState & MK_ALT)    &&
        !(grfKeyState & MK_RBUTTON) &&
        !(grfKeyState & MK_SHIFT))
    {
        if( nSourceActions & ACTION_MOVE )
        {
            ret= ACTION_DEFAULT | ACTION_MOVE;
        }

        else if( nSourceActions & ACTION_COPY )
        {
            ret= ACTION_COPY;
        }

        else if( nSourceActions & ACTION_LINK )
        {
            ret= ACTION_LINK;
        }

        else
            ret = 0;
    }
    else if( grfKeyState & MK_SHIFT &&
            !(grfKeyState & MK_CONTROL))
    {
        ret= ACTION_MOVE;
    }
    else if ( grfKeyState & MK_CONTROL &&
              !(grfKeyState & MK_SHIFT) )
    {
        ret= ACTION_COPY;
    }
    else if ( grfKeyState & MK_CONTROL &&
              grfKeyState & MK_SHIFT)
    {
        ret= ACTION_LINK;
    }
    else if ( grfKeyState & MK_RBUTTON |
              grfKeyState & MK_ALT)
    {
        ret= ACTION_COPY_OR_MOVE | ACTION_LINK;
    }
    return ret;
}

sal_Int8 dndOleDropEffectsToActions( DWORD dwEffect)
{
    sal_Int8 ret= ACTION_NONE;
    if( dwEffect & DROPEFFECT_COPY)
        ret |= ACTION_COPY;
    if( dwEffect & DROPEFFECT_MOVE)
        ret |= ACTION_MOVE;
    if( dwEffect & DROPEFFECT_LINK)
        ret |= ACTION_LINK;

    return ret;
}

DWORD dndActionsToDropEffects( sal_Int8 actions)
{
    DWORD ret= DROPEFFECT_NONE;
    if( actions & ACTION_MOVE)
        ret |= DROPEFFECT_MOVE;
    if( actions & ACTION_COPY)
        ret |= DROPEFFECT_COPY;
    if( actions & ACTION_LINK)
        ret |= DROPEFFECT_LINK;
    if( actions & ACTION_DEFAULT)
        ret |= DROPEFFECT_COPY;
    return ret;
}

DWORD dndActionsToSingleDropEffect( sal_Int8 actions)
{
    DWORD effects= dndActionsToDropEffects( actions);

    sal_Int8 countEffect= 0;

    if( effects & DROPEFFECT_MOVE)
        countEffect++;
    if( effects & DROPEFFECT_COPY)
        countEffect++;
    if( effects & DROPEFFECT_LINK)
        countEffect++;

    // DROPEFFECT_MOVE is the default effect
    DWORD retVal= countEffect > 1 ? DROPEFFECT_MOVE : effects;
    return retVal;
}
<commit_msg>INTEGRATION: CWS ooo19126 (1.7.176); FILE MERGED 2005/09/05 18:48:16 rt 1.7.176.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: globals.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 18:16:38 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANTS_HPP_
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
#endif

#include "globals.hxx"

//--> TRA
#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

// used as shortcut when drag-source and drop-target are the same
::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > g_XTransferable;

//<-- TRA

using namespace com::sun::star::datatransfer::dnd::DNDConstants;

sal_Int8 dndOleKeysToAction( DWORD grfKeyState, sal_Int8 nSourceActions)
{
    sal_Int8 ret= 0;

    // no MK_ALT, MK_CONTROL, MK_SHIFT
    if( !(grfKeyState & MK_CONTROL) &&
        !(grfKeyState & MK_ALT)    &&
        !(grfKeyState & MK_RBUTTON) &&
        !(grfKeyState & MK_SHIFT))
    {
        if( nSourceActions & ACTION_MOVE )
        {
            ret= ACTION_DEFAULT | ACTION_MOVE;
        }

        else if( nSourceActions & ACTION_COPY )
        {
            ret= ACTION_COPY;
        }

        else if( nSourceActions & ACTION_LINK )
        {
            ret= ACTION_LINK;
        }

        else
            ret = 0;
    }
    else if( grfKeyState & MK_SHIFT &&
            !(grfKeyState & MK_CONTROL))
    {
        ret= ACTION_MOVE;
    }
    else if ( grfKeyState & MK_CONTROL &&
              !(grfKeyState & MK_SHIFT) )
    {
        ret= ACTION_COPY;
    }
    else if ( grfKeyState & MK_CONTROL &&
              grfKeyState & MK_SHIFT)
    {
        ret= ACTION_LINK;
    }
    else if ( grfKeyState & MK_RBUTTON |
              grfKeyState & MK_ALT)
    {
        ret= ACTION_COPY_OR_MOVE | ACTION_LINK;
    }
    return ret;
}

sal_Int8 dndOleDropEffectsToActions( DWORD dwEffect)
{
    sal_Int8 ret= ACTION_NONE;
    if( dwEffect & DROPEFFECT_COPY)
        ret |= ACTION_COPY;
    if( dwEffect & DROPEFFECT_MOVE)
        ret |= ACTION_MOVE;
    if( dwEffect & DROPEFFECT_LINK)
        ret |= ACTION_LINK;

    return ret;
}

DWORD dndActionsToDropEffects( sal_Int8 actions)
{
    DWORD ret= DROPEFFECT_NONE;
    if( actions & ACTION_MOVE)
        ret |= DROPEFFECT_MOVE;
    if( actions & ACTION_COPY)
        ret |= DROPEFFECT_COPY;
    if( actions & ACTION_LINK)
        ret |= DROPEFFECT_LINK;
    if( actions & ACTION_DEFAULT)
        ret |= DROPEFFECT_COPY;
    return ret;
}

DWORD dndActionsToSingleDropEffect( sal_Int8 actions)
{
    DWORD effects= dndActionsToDropEffects( actions);

    sal_Int8 countEffect= 0;

    if( effects & DROPEFFECT_MOVE)
        countEffect++;
    if( effects & DROPEFFECT_COPY)
        countEffect++;
    if( effects & DROPEFFECT_LINK)
        countEffect++;

    // DROPEFFECT_MOVE is the default effect
    DWORD retVal= countEffect > 1 ? DROPEFFECT_MOVE : effects;
    return retVal;
}
<|endoftext|>


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

#include <cmath>   // rand()
#include <sstream>

#include <os>
#include <net/inet4>
#include <net/dhcp/dh4client.hpp>

using namespace std::chrono;

std::string HTML_RESPONSE();

void create_server(net::TCP::Connection& conn)
{
  // Add a TCP connection handler - here a hardcoded HTTP-service
  conn.onAccept(
  [] (auto conn) -> bool
  {
    printf("<Service> @onAccept - Connection attempt from: %s \n",
           conn->to_string().c_str());
    return true; // allow all connections

  }).onConnect(
  [] (auto conn) {
    printf("<Service> @onConnect - Connection successfully established.\n");
    // read async with a buffer size of 1024 bytes
    // define what to do when data is read
    conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) {
        // create string from buffer
        std::string data { (char*)buf.get(), n };
        printf("<Service> @read:\n%s\n", data.c_str());

        // create response
        std::string response = HTML_RESPONSE();
        // write the data from the string with the strings size
        conn->write(response.data(), response.size(), [](size_t n) {
            printf("<Service> @write: %u bytes written\n", n);
          });
      });

  }).onDisconnect(
  [] (auto conn, auto reason) {
      printf("<Service> @onDisconnect - Reason: %s \n", reason.to_string().c_str());
      conn->close();
  });
}

void Service::start() {
  srand(OS::cycles_since_boot());

  // Two IP-stack objects

  // Stack with network interface (eth0) driven by VirtioNet
  // DNS address defaults to 8.8.8.8
  // Static IP configuration, until we (possibly) get DHCP
  // @note : Mostly to get a robust demo service that works with and without DHCP
  static auto inet1 = net::new_ipv4_stack<>({ 10,0,0,42 },      // IP
                                            { 255,255,255,0 },  // Netmask
                                            { 10,0,0,1 });      // Gateway

  // Assign a driver (VirtioNet) to network interface (eth1)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which we want to avoid.
  static auto inet2 = net::new_ipv4_stack<1,VirtioNet>({ 20,0,0,42 },      // IP
                                                       { 255,255,255,0 },  // Netmask
                                                       { 20,0,0,1 });      // Gateway
  // Set up a TCP server on port 80
  auto& server1 = inet1->tcp().bind(80);
  create_server(server1);

  auto& server2 = inet2->tcp().bind(80);
  create_server(server2);

  // Print some useful netstats every 30 secs
  hw::PIT::instance().onRepeatedTimeout(30s, [] {
    printf("<INET_1> TCP STATUS:\n\t%s\n", inet1->tcp().status().c_str());
    printf("<INET_2> TCP STATUS:\n\t%s\n", inet2->tcp().status().c_str());
  });

  printf("*** TEST SERVICE STARTED *** \n");
}

std::string HTML_RESPONSE() {
  const int color = rand();

  /* HTML Fonts */
  const std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
  const std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
  const std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

  /* HTML */
  std::stringstream stream;
  stream << "<!DOCTYPE html>"
         << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
         << ""
         << "<h1 style='color: #" << std::hex << (color >> 8) << "'>"
         <<  "IncludeOS
"
         <<  "
Now speaks TCP!
"
         // .... generate more dynamic content
         << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
         << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
         << "";

  const std::string html = stream.str();

  const std::string header
  {
    "HTTP/1.1 200 OK\n"
    "Date: Mon, 01 Jan 1970 00:00:01 GMT\n"
    "Server: IncludeOS prototype 4.0\n"
    "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\n"
    "Content-Type: text/html; charset=UTF-8\n"
    "Content-Length: "+std::to_string(html.size())+"\n"
    "Accept-Ranges: bytes\n"
    "Connection: close\n\n"
  };

  return header + html;
}
<commit_msg>Tightened up newlines in output<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cmath>   // rand()
#include <sstream>

#include <os>
#include <net/inet4>
#include <net/dhcp/dh4client.hpp>

using namespace std::chrono;

std::string HTML_RESPONSE();

void create_server(net::TCP::Connection& conn)
{
  // Add a TCP connection handler - here a hardcoded HTTP-service
  conn.onAccept(
  [] (auto conn) -> bool
  {
    printf("<Service> @onAccept - Connection attempt from: %s\n",
           conn->to_string().c_str());
    return true; // allow all connections

  }).onConnect(
  [] (auto conn) {
    printf("<Service> @onConnect - Connection successfully established.\n");
    // read async with a buffer size of 1024 bytes
    // define what to do when data is read
    conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) {
        // create string from buffer
        std::string data { (char*)buf.get(), n };
        printf("<Service> @read:\n%s\n", data.c_str());

        // create response
        std::string response = HTML_RESPONSE();
        // write the data from the string with the strings size
        conn->write(response.data(), response.size(), [](size_t n) {
            printf("<Service> @write: %u bytes written\n", n);
          });
      });

  }).onDisconnect(
  [] (auto conn, auto reason) {
      printf("<Service> @onDisconnect - Reason: %s\n", reason.to_string().c_str());
      conn->close();
  });
}

void Service::start() {
  srand(OS::cycles_since_boot());

  // Two IP-stack objects

  // Stack with network interface (eth0) driven by VirtioNet
  // DNS address defaults to 8.8.8.8
  // Static IP configuration, until we (possibly) get DHCP
  // @note : Mostly to get a robust demo service that works with and without DHCP
  static auto inet1 = net::new_ipv4_stack<>({ 10,0,0,42 },      // IP
                                            { 255,255,255,0 },  // Netmask
                                            { 10,0,0,1 });      // Gateway

  // Assign a driver (VirtioNet) to network interface (eth1)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which we want to avoid.
  static auto inet2 = net::new_ipv4_stack<1,VirtioNet>({ 20,0,0,42 },      // IP
                                                       { 255,255,255,0 },  // Netmask
                                                       { 20,0,0,1 });      // Gateway
  // Set up a TCP server on port 80
  auto& server1 = inet1->tcp().bind(80);
  create_server(server1);

  auto& server2 = inet2->tcp().bind(80);
  create_server(server2);

  // Print some useful netstats every 30 secs
  hw::PIT::instance().onRepeatedTimeout(30s, [] {
    printf("<INET_1> TCP STATUS:\n\t%s\n", inet1->tcp().status().c_str());
    printf("<INET_2> TCP STATUS:\n\t%s\n", inet2->tcp().status().c_str());
  });

  printf("*** TEST SERVICE STARTED ***\n");
}

std::string HTML_RESPONSE() {
  const int color = rand();

  /* HTML Fonts */
  const std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
  const std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
  const std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

  /* HTML */
  std::stringstream stream;
  stream << "<!DOCTYPE html>"
         << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
         << ""
         << "<h1 style='color: #" << std::hex << (color >> 8) << "'>"
         <<  "IncludeOS
"
         <<  "
Now speaks TCP!
"
         // .... generate more dynamic content
         << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
         << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
         << "";

  const std::string html = stream.str();

  const std::string header
  {
    "HTTP/1.1 200 OK\n"
    "Date: Mon, 01 Jan 1970 00:00:01 GMT\n"
    "Server: IncludeOS prototype 4.0\n"
    "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\n"
    "Content-Type: text/html; charset=UTF-8\n"
    "Content-Length: "+std::to_string(html.size())+'\n'
    "Accept-Ranges: bytes\n"
    "Connection: close\n\n"
  };

  return header + html;
}
<|endoftext|>