<commit_before>/*
 * File:   main.cpp
 * Author: Jukka Vatjus-Anttila
 *
 * Created on January 23, 2012, 8:02 PM
 */
#include <iostream>
#include <cstdlib>
#include <sstream>
#include "cGameEntity.h"
#include "cTowerEntity.h"
#include "cEnemyEntity.h"
#include "cMapper.h"
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>

using namespace std;
/*
 *
 */
int main(int argc, char** argv)
{
    cout << "Hello tower defense!\n";

    bool appRunning = true;

    // Initialize variables for gameloop timer logic
    sf::Clock clock;
    const int framerate = 60;
    float framestartTime = 0; //fix this
    float difference = 0;
    float sleepTime = 0;
    float frameBudget = 1/(float)framerate;

    // Create SFML renderwindow
    sf::RenderWindow window(sf::VideoMode(800,600,32), "Tower-Defence!", sf::Style::Close);

    // Create event mapper
    sf::Event Event;

    // Testing renderwindow draw shapes and text
    sf::Shape towerShape = sf::Shape::Circle(0.f, 0.f, 5.f, sf::Color::White);
    sf::Shape enemyShape = sf::Shape::Rectangle(0.f, 0.f, 10.f, 10.f, sf::Color::Blue);
    sf::String text("Frametime");

    // Inputmapper
    const sf::Input& Input = window.GetInput();

    // Singleton mapper class which updates all gameEntities
    cMapper *mapper;

    try {
        mapper = cMapper::getInstance();
    } catch (bad_alloc&) {
        return EXIT_FAILURE;
    }

    // Start running the clock just before gameloop
    clock.Reset();

    // Gameloop
    while(appRunning)
    {
        window.Clear();

        std::ostringstream frametimer;
        frametimer << framestartTime;
        std::string buffer;
        buffer.append("Frametime: ").append(frametimer.str());
        text.SetText(buffer);

        std::vector<cGameEntity*> entityList = mapper->getEntities();
        std::vector<cGameEntity*>::iterator iter = entityList.begin();
        for (;iter < entityList.end(); iter++)
        {
            if ((*iter)->name() == "Enemy")
            {
                enemyShape.SetPosition((*iter)->getXPosition(), (*iter)->getYPosition());
                window.Draw(enemyShape);
            }
            else
            {
                towerShape.SetPosition((*iter)->getXPosition(), (*iter)->getYPosition());
                window.Draw(towerShape);
            }
        }

        window.Draw(text);
        window.Display();

        // Get current framestart time
        framestartTime = clock.GetElapsedTime();

        // Update game logic. Here only mapper->update()
        mapper->update(framestartTime);

        // Get time elapsed in game logic update
        difference = clock.GetElapsedTime() - framestartTime;

        // If difference is smaller than budgeted, rest until next frame
        if (difference < frameBudget)
        {
            // Rendering budgets:
            // 60fps = 16,667ms
            // 30fps = 33,333ms
            // 10fps = 100ms
            //  5fps = 200ms
            sleepTime = frameBudget - difference;
            // Sleep for rest of the frame
            sf::Sleep(sleepTime);
        }

        // Event loop checker
        while (window.GetEvent(Event))
        {
            // Window closed
            if (Event.Type == sf::Event::Closed)
            {
                cout << "User interrupt close window!\n";
                appRunning = false;
                window.Close();
            }

            // Escape key pressed
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
            {
                cout << "User interrupt ESC-key!\n";
                appRunning = false;
                window.Close();
            }

            // Mouse button left pressed
            if ((Event.Type == sf::Event::MouseButtonPressed) && (Event.Key.Code == sf::Mouse::Left))
            {
                mapper->add(dynamic_cast<cGameEntity*> (new cTowerEntity(Input.GetMouseX(),Input.GetMouseY())));
            }

            // Mouse button right pressed
            if ((Event.Type == sf::Event::MouseButtonPressed) && (Event.Key.Code == sf::Mouse::Right))
            {
                mapper->add(dynamic_cast<cGameEntity*> (new cEnemyEntity(Input.GetMouseX(),Input.GetMouseY())));
            }
        }
    }
    // End of gameloop. Destroy mapper.
    delete mapper;

    return EXIT_SUCCESS;
}

<commit_msg>Master branch diverge test.<commit_after>/*
 * File:   main.cpp
 * Author: Jukka Vatjus-Anttila
 *
 * Created on January 23, 2012, 8:02 PM
 */
#include <iostream>
#include <cstdlib>
#include <sstream>
#include "cGameEntity.h"
#include "cTowerEntity.h"
#include "cEnemyEntity.h"
#include "cMapper.h"
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>

using namespace std;
/*
 *
 */
int main(int argc, char** argv)
{
    cout << "Hello tower defense - master branch!\n";

    bool appRunning = true;

    // Initialize variables for gameloop timer logic
    sf::Clock clock;
    const int framerate = 60;
    float framestartTime = 0; //fix this
    float difference = 0;
    float sleepTime = 0;
    float frameBudget = 1/(float)framerate;

    // Create SFML renderwindow
    sf::RenderWindow window(sf::VideoMode(800,600,32), "Tower-Defence!", sf::Style::Close);

    // Create event mapper
    sf::Event Event;

    // Testing renderwindow draw shapes and text
    sf::Shape towerShape = sf::Shape::Circle(0.f, 0.f, 5.f, sf::Color::White);
    sf::Shape enemyShape = sf::Shape::Rectangle(0.f, 0.f, 10.f, 10.f, sf::Color::Blue);
    sf::String text("Frametime");

    // Inputmapper
    const sf::Input& Input = window.GetInput();

    // Singleton mapper class which updates all gameEntities
    cMapper *mapper;

    try {
        mapper = cMapper::getInstance();
    } catch (bad_alloc&) {
        return EXIT_FAILURE;
    }

    // Start running the clock just before gameloop
    clock.Reset();

    // Gameloop
    while(appRunning)
    {
        window.Clear();

        std::ostringstream frametimer;
        frametimer << framestartTime;
        std::string buffer;
        buffer.append("Frametime: ").append(frametimer.str());
        text.SetText(buffer);

        std::vector<cGameEntity*> entityList = mapper->getEntities();
        std::vector<cGameEntity*>::iterator iter = entityList.begin();
        for (;iter < entityList.end(); iter++)
        {
            if ((*iter)->name() == "Enemy")
            {
                enemyShape.SetPosition((*iter)->getXPosition(), (*iter)->getYPosition());
                window.Draw(enemyShape);
            }
            else
            {
                towerShape.SetPosition((*iter)->getXPosition(), (*iter)->getYPosition());
                window.Draw(towerShape);
            }
        }

        window.Draw(text);
        window.Display();

        // Get current framestart time
        framestartTime = clock.GetElapsedTime();

        // Update game logic. Here only mapper->update()
        mapper->update(framestartTime);

        // Get time elapsed in game logic update
        difference = clock.GetElapsedTime() - framestartTime;

        // If difference is smaller than budgeted, rest until next frame
        if (difference < frameBudget)
        {
            // Rendering budgets:
            // 60fps = 16,667ms
            // 30fps = 33,333ms
            // 10fps = 100ms
            //  5fps = 200ms
            sleepTime = frameBudget - difference;
            // Sleep for rest of the frame
            sf::Sleep(sleepTime);
        }

        // Event loop checker
        while (window.GetEvent(Event))
        {
            // Window closed
            if (Event.Type == sf::Event::Closed)
            {
                cout << "User interrupt close window!\n";
                appRunning = false;
                window.Close();
            }

            // Escape key pressed
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
            {
                cout << "User interrupt ESC-key!\n";
                appRunning = false;
                window.Close();
            }

            // Mouse button left pressed
            if ((Event.Type == sf::Event::MouseButtonPressed) && (Event.Key.Code == sf::Mouse::Left))
            {
                mapper->add(dynamic_cast<cGameEntity*> (new cTowerEntity(Input.GetMouseX(),Input.GetMouseY())));
            }

            // Mouse button right pressed
            if ((Event.Type == sf::Event::MouseButtonPressed) && (Event.Key.Code == sf::Mouse::Right))
            {
                mapper->add(dynamic_cast<cGameEntity*> (new cEnemyEntity(Input.GetMouseX(),Input.GetMouseY())));
            }
        }
    }
    // End of gameloop. Destroy mapper.
    delete mapper;

    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#ifndef COBALT_EVENTS_HPP_INCLUDED
#define COBALT_EVENTS_HPP_INCLUDED

#pragma once

// Classes in this file:
//     event
//     basic_event
//     rebind_event_handler
//     event_dispatcher
//     event_subscriber
//     event_target

#include <cobalt/utility/intrusive.hpp>
#include <cobalt/utility/hash.hpp>
#include <cobalt/utility/enum_traits.hpp>

#include <boost/assert.hpp>

#include <array>
#include <deque>
#include <unordered_map>
#include <chrono>

CO_DEFINE_ENUM_CLASS(
	event_phase, uint8_t,
	bubbling,
	capture,
	sinking
)

CO_DEFINE_ENUM_FLAGS_CLASS(
	subscribe_mode, uint8_t,
	type = 1 << 0,
	name = 1 << 1,
	type_and_name = type | name
)

namespace cobalt {

/// event
class event : public ref_counter<event> {
public:
	typedef hash_type target_type;

	virtual ~event() = default;
	virtual target_type target() const = 0;
};

/// basic_event
template <event::target_type Target>
class basic_event : public event {
public:
	static constexpr target_type type = Target;

	virtual target_type target() const override { return Target; }
};

#define CO_DEFINE_EVENT_CLASS(event_class_name) class event_class_name : public basic_event<#event_class_name##_hash>

/// rebind_event_handler
template
<
	typename T,
	typename E,
	typename = typename std::enable_if<std::is_base_of<event, E>::value>::type
>
class rebind_event_handler {
public:
	rebind_event_handler(void(T::*mf)(E*), T* obj)
		: _obj(obj)
		, _mf(mf)
	{
	}

	void operator()(event* ev) {
		(_obj->*_mf)(static_cast<E*>(ev));
	}

	friend bool operator==(const rebind_event_handler& rhs, const rebind_event_handler& lhs) {
		return rhs._obj == lhs._obj && rhs._mf == lhs._mf;
	}

private:
	T* _obj;
	void(T::*_mf)(E*);
};

/// event_dispatcher
class event_dispatcher {
public:
	typedef event::target_type target_type;
	typedef std::function<void(event*)> handler_type;
	typedef std::chrono::high_resolution_clock clock_type;

	event_dispatcher() = default;

	// subscribe/subscribed/unsubscribe

	size_t subscribe(target_type target, handler_type handler) {
		size_t handler_hash = handler.target_type().hash_code();
		_handlers.emplace(target, std::move(handler));
		return handler_hash;
	}

	bool subscribed(target_type target, handler_type handler) const {
		return subscribed(target, handler.target_type().hash_code());
	}

	bool subscribed(target_type target, size_t handler_hash) const {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash)
				return true;
		}
		return false;
	}

	bool unsubscribe(target_type target, handler_type handler) {
		return unsubscribe(target, handler.target_type().hash_code());
	}

	bool unsubscribe(target_type target, size_t handler_hash) {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash) {
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// subscribe/subscribed/unsubscribe templated overloads for member functions

	template <typename T, typename E>
	size_t subscribe(void(T::*mf)(E*), T* obj) {
		subscribe(E::type, rebind_event_handler<T, E>(mf, obj));
		return typeid(rebind_event_handler<T, E>).hash_code();
	}

	template <typename T, typename E>
	bool subscribed(void(T::*mf)(E*), T* obj) const {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj))
				return true;
		}
		return false;
	}

	template <typename T, typename E>
	bool unsubscribe(void(T::*mf)(E*), T* obj, size_t* handler_hash = nullptr) {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj)) {
				if (handler_hash)
					*handler_hash = (*it).second.target_type().hash_code();
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// post/dispatch/invoke

	bool empty() const {
		return _queues[0].empty();
	}

	void post(const ref_ptr<event>& event) {
		_queues[0].emplace_back(event->target(), event);
	}

	void post(ref_ptr<event>&& event) {
		_queues[0].emplace_back(event->target(), std::move(event));
	}

	void post(target_type target, const ref_ptr<event>& event) {
		_queues[0].emplace_back(target, event);
	}

	void post(target_type target, ref_ptr<event>&& event) {
		_queues[0].emplace_back(target, std::move(event));
	}

	bool posted(target_type target) const {
		for (auto&& p : _queues[0]) {
			if (p.first == target)
				return true;
		}
		return false;
	}

	bool abort_first(target_type target) {
		auto it = std::find_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end()) {
			_queues[0].erase(it);
			return true;
		}

		return false;
	}

	bool abort_last(target_type target) {
		auto it = std::find_if(_queues[0].rbegin(), _queues[0].rend(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].rend()) {
			_queues[0].erase(--it.base());
			return true;
		}

		return false;
	}

	void abort_all(target_type target) {
		auto it = std::remove_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end())
			_queues[0].erase(it, _queues[0].end());
	}

	/// Dispatches events with timeout
	/// @return Number of invoked handlers
	size_t dispatch(clock_type::duration timeout) {
		size_t count = 0;

		std::swap(_queues[0], _queues[1]);

		auto start = clock_type::now();

		while (!_queues[1].empty()) {
			auto&& p = _queues[1].front();
			count += invoke(p.first, p.second);
			_queues[1].pop_front();

			if (clock_type::now() - start >= timeout)
				break;
		}

		// Insert not processed events to the main queue
		if (!_queues[1].empty()) {
			_queues[0].insert(_queues[0].begin(),
				std::make_move_iterator(_queues[1].begin()),
				std::make_move_iterator(_queues[1].end()));

			_queues[1].clear();
		}

		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(event->target());
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(target_type target, const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

private:
	typedef std::unordered_multimap<target_type, handler_type, dont_hash<target_type>> Handlers;
	Handlers _handlers;

	typedef std::deque<std::pair<target_type, ref_ptr<event>>> Events;
	std::array<Events, 2> _queues;
};

/// Helper base class for objects to subscribe to and automatically unsubscribe from events
template <typename T>
class event_subscriber {
public:
	explicit event_subscriber(event_dispatcher& dispatcher)
		: _dispatcher(dispatcher)
	{
	}

	~event_subscriber() {
		for (auto&& s : _subscriptions) {
			BOOST_VERIFY(_dispatcher.unsubscribe(s.first, s.second));
		}
	}

	template <typename E>
	void subscribe(void(T::*mf)(E*)) {
		auto handler_hash = _dispatcher.subscribe(mf, static_cast<T*>(this));
		_subscriptions.emplace_back(E::type, handler_hash);
	}

	template <typename E>
	bool subscribed(void(T::*mf)(E*)) const {
		return _dispatcher.subscribed(mf, static_cast<T*>(this));
	}

	template <typename E>
	void unsubscribe(void(T::*mf)(E*)) {
		size_t handler_hash = 0;
		BOOST_VERIFY(_dispatcher.unsubscribe(mf, static_cast<T*>(this), &handler_hash));
		// Remove handler hash for event type from subscriptions
		auto it = std::find(_subscriptions.begin(), _subscriptions.end(), std::make_pair(E::type, handler_hash));
		if (it != _subscriptions.end())
			_subscriptions.erase(it);
	}

private:
	event_dispatcher& _dispatcher;

	typedef std::deque<std::pair<event_dispatcher::target_type, size_t>> Subscriptions;
	Subscriptions _subscriptions;
};

/// Base class for objects to make them event targets
template
<
	typename T,
	subscribe_mode Mode = subscribe_mode::type_and_name
>
class event_target {
public:
	explicit event_target(event_dispatcher& dispatcher, const char* target_name = nullptr)
		: _dispatcher(dispatcher)
		, _target(get_target(target_name))
	{
		using std::placeholders::_1;

		event_dispatcher::handler_type handler = std::bind(&event_target::on_event, static_cast<T*>(this), _1);
		_handler_hash = _dispatcher.subscribe(_target, handler);
	}

	virtual ~event_target() {
		BOOST_VERIFY(_dispatcher.unsubscribe(_target, _handler_hash));
	}

	virtual void on_event(event*) = 0;

	static event_dispatcher::target_type get_target(const char* target_name) {
		static_assert(std::is_same<event_dispatcher::target_type, hash_type>::value, "target_type is not hash_type");

		hash_type hash_value = 0;

		if ((Mode & subscribe_mode::type) == subscribe_mode::type)
			hash_value = typeid(T).hash_code();

		if ((Mode & subscribe_mode::name) == subscribe_mode::name && target_name != nullptr)
			hash_value = murmur3(target_name, std::strlen(target_name), hash_value);

		BOOST_ASSERT_MSG(hash_value != 0, "Cannot identify target");

		return hash_value;
	}

private:
	event_dispatcher& _dispatcher;
	event_dispatcher::target_type _target = 0;
	size_t _handler_hash = 0;
};

} // namespace cobalt

#endif // COBALT_EVENTS_HPP_INCLUDED
<commit_msg>Restricted copying policy for some classes<commit_after>#ifndef COBALT_EVENTS_HPP_INCLUDED
#define COBALT_EVENTS_HPP_INCLUDED

#pragma once

// Classes in this file:
//     event
//     basic_event
//     rebind_event_handler
//     event_dispatcher
//     event_subscriber
//     event_target

#include <cobalt/utility/intrusive.hpp>
#include <cobalt/utility/hash.hpp>
#include <cobalt/utility/enum_traits.hpp>

#include <boost/assert.hpp>

#include <array>
#include <deque>
#include <unordered_map>
#include <chrono>

CO_DEFINE_ENUM_CLASS(
	event_phase, uint8_t,
	bubbling,
	capture,
	sinking
)

CO_DEFINE_ENUM_FLAGS_CLASS(
	subscribe_mode, uint8_t,
	type = 1 << 0,
	name = 1 << 1,
	type_and_name = type | name
)

namespace cobalt {

/// event
class event : public ref_counter<event> {
public:
	typedef hash_type target_type;

	virtual ~event() = default;
	virtual target_type target() const = 0;
};

/// basic_event
template <event::target_type Target>
class basic_event : public event {
public:
	static constexpr target_type type = Target;

	virtual target_type target() const override { return Target; }
};

#define CO_DEFINE_EVENT_CLASS(event_class_name) class event_class_name : public basic_event<#event_class_name##_hash>

/// rebind_event_handler
template
<
	typename T,
	typename E,
	typename = typename std::enable_if<std::is_base_of<event, E>::value>::type
>
class rebind_event_handler {
public:
	rebind_event_handler(void(T::*mf)(E*), T* obj)
		: _obj(obj)
		, _mf(mf)
	{
	}

	void operator()(event* ev) {
		(_obj->*_mf)(static_cast<E*>(ev));
	}

	friend bool operator==(const rebind_event_handler& rhs, const rebind_event_handler& lhs) {
		return rhs._obj == lhs._obj && rhs._mf == lhs._mf;
	}

private:
	T* _obj;
	void(T::*_mf)(E*);
};

/// event_dispatcher
class event_dispatcher {
public:
	typedef event::target_type target_type;
	typedef std::function<void(event*)> handler_type;
	typedef std::chrono::high_resolution_clock clock_type;

	event_dispatcher() = default;

	event_dispatcher(const event_dispatcher&) = delete;
	event_dispatcher& operator=(const event_dispatcher&) = delete;

	// subscribe/subscribed/unsubscribe

	size_t subscribe(target_type target, handler_type handler) {
		size_t handler_hash = handler.target_type().hash_code();
		_handlers.emplace(target, std::move(handler));
		return handler_hash;
	}

	bool subscribed(target_type target, handler_type handler) const {
		return subscribed(target, handler.target_type().hash_code());
	}

	bool subscribed(target_type target, size_t handler_hash) const {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash)
				return true;
		}
		return false;
	}

	bool unsubscribe(target_type target, handler_type handler) {
		return unsubscribe(target, handler.target_type().hash_code());
	}

	bool unsubscribe(target_type target, size_t handler_hash) {
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it) {
			auto&& typeinfo = (*it).second.target_type();
			if (typeinfo.hash_code() == handler_hash) {
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// subscribe/subscribed/unsubscribe templated overloads for member functions

	template <typename T, typename E>
	size_t subscribe(void(T::*mf)(E*), T* obj) {
		subscribe(E::type, rebind_event_handler<T, E>(mf, obj));
		return typeid(rebind_event_handler<T, E>).hash_code();
	}

	template <typename T, typename E>
	bool subscribed(void(T::*mf)(E*), T* obj) const {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj))
				return true;
		}
		return false;
	}

	template <typename T, typename E>
	bool unsubscribe(void(T::*mf)(E*), T* obj, size_t* handler_hash = nullptr) {
		auto range = _handlers.equal_range(E::type);
		for (auto it = range.first; it != range.second; ++it) {
			auto target = (*it).second.template target<rebind_event_handler<T, E>>();
			if (target && *target == rebind_event_handler<T, E>(mf, obj)) {
				if (handler_hash)
					*handler_hash = (*it).second.target_type().hash_code();
				_handlers.erase(it);
				return true;
			}
		}
		return false;
	}

	// post/dispatch/invoke

	bool empty() const {
		return _queues[0].empty();
	}

	void post(const ref_ptr<event>& event) {
		_queues[0].emplace_back(event->target(), event);
	}

	void post(ref_ptr<event>&& event) {
		_queues[0].emplace_back(event->target(), std::move(event));
	}

	void post(target_type target, const ref_ptr<event>& event) {
		_queues[0].emplace_back(target, event);
	}

	void post(target_type target, ref_ptr<event>&& event) {
		_queues[0].emplace_back(target, std::move(event));
	}

	bool posted(target_type target) const {
		for (auto&& p : _queues[0]) {
			if (p.first == target)
				return true;
		}
		return false;
	}

	bool abort_first(target_type target) {
		auto it = std::find_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end()) {
			_queues[0].erase(it);
			return true;
		}

		return false;
	}

	bool abort_last(target_type target) {
		auto it = std::find_if(_queues[0].rbegin(), _queues[0].rend(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].rend()) {
			_queues[0].erase(--it.base());
			return true;
		}

		return false;
	}

	void abort_all(target_type target) {
		auto it = std::remove_if(_queues[0].begin(), _queues[0].end(),
			[&](const Events::value_type& v) {
				return v.first == target;
			});

		if (it != _queues[0].end())
			_queues[0].erase(it, _queues[0].end());
	}

	/// Dispatches events with timeout
	/// @return Number of invoked handlers
	size_t dispatch(clock_type::duration timeout) {
		size_t count = 0;

		std::swap(_queues[0], _queues[1]);

		auto start = clock_type::now();

		while (!_queues[1].empty()) {
			auto&& p = _queues[1].front();
			count += invoke(p.first, p.second);
			_queues[1].pop_front();

			if (clock_type::now() - start >= timeout)
				break;
		}

		// Insert not processed events to the main queue
		if (!_queues[1].empty()) {
			_queues[0].insert(_queues[0].begin(),
				std::make_move_iterator(_queues[1].begin()),
				std::make_move_iterator(_queues[1].end()));

			_queues[1].clear();
		}

		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(event->target());
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

	/// Invokes the event immediately
	/// @return Number of invoked handlers
	size_t invoke(target_type target, const ref_ptr<event>& event) {
		size_t count = 0;
		auto range = _handlers.equal_range(target);
		for (auto it = range.first; it != range.second; ++it, ++count)
			(*it).second(event.get());
		return count;
	}

private:
	typedef std::unordered_multimap<target_type, handler_type, dont_hash<target_type>> Handlers;
	Handlers _handlers;

	typedef std::deque<std::pair<target_type, ref_ptr<event>>> Events;
	std::array<Events, 2> _queues;
};

/// Helper base class for objects to subscribe to and automatically unsubscribe from events
template <typename T>
class event_subscriber {
public:
	explicit event_subscriber(event_dispatcher& dispatcher)
		: _dispatcher(dispatcher)
	{
	}

	~event_subscriber() {
		for (auto&& s : _subscriptions) {
			BOOST_VERIFY(_dispatcher.unsubscribe(s.first, s.second));
		}
	}

	event_subscriber(const event_subscriber&) = delete;
	event_subscriber& operator=(const event_subscriber&) = delete;

	template <typename E>
	void subscribe(void(T::*mf)(E*)) {
		auto handler_hash = _dispatcher.subscribe(mf, static_cast<T*>(this));
		_subscriptions.emplace_back(E::type, handler_hash);
	}

	template <typename E>
	bool subscribed(void(T::*mf)(E*)) const {
		return _dispatcher.subscribed(mf, static_cast<T*>(this));
	}

	template <typename E>
	void unsubscribe(void(T::*mf)(E*)) {
		size_t handler_hash = 0;
		BOOST_VERIFY(_dispatcher.unsubscribe(mf, static_cast<T*>(this), &handler_hash));
		// Remove handler hash for event type from subscriptions
		auto it = std::find(_subscriptions.begin(), _subscriptions.end(), std::make_pair(E::type, handler_hash));
		if (it != _subscriptions.end())
			_subscriptions.erase(it);
	}

private:
	event_dispatcher& _dispatcher;

	typedef std::deque<std::pair<event_dispatcher::target_type, size_t>> Subscriptions;
	Subscriptions _subscriptions;
};

/// Base class for objects to make them event targets
template
<
	typename T,
	subscribe_mode Mode = subscribe_mode::type_and_name
>
class event_target {
public:
	explicit event_target(event_dispatcher& dispatcher, const char* target_name = nullptr)
		: _dispatcher(dispatcher)
		, _target(make_target(target_name))
	{
		using std::placeholders::_1;
		_handler = _dispatcher.subscribe(_target, std::bind(&event_target::on_event, static_cast<T*>(this), _1));
	}

	virtual ~event_target() {
		BOOST_VERIFY(_dispatcher.unsubscribe(_target, _handler));
	}

	event_target(const event_target&) = delete;
	event_target& operator=(const event_target&) = delete;

	virtual void on_event(event*) = 0;

private:
	static event_dispatcher::target_type make_target(const char* target_name) {
		static_assert(std::is_same<event_dispatcher::target_type, hash_type>::value, "target_type is not hash_type");

		hash_type hash_value = 0;

		if ((Mode & subscribe_mode::type) == subscribe_mode::type)
			hash_value = typeid(T).hash_code();

		if ((Mode & subscribe_mode::name) == subscribe_mode::name && target_name != nullptr)
			hash_value = murmur3(target_name, std::strlen(target_name), hash_value);

		BOOST_ASSERT_MSG(hash_value != 0, "Cannot identify target");

		return hash_value;
	}

private:
	event_dispatcher& _dispatcher;
	event_dispatcher::target_type _target = 0;
	size_t _handler = 0;
};

} // namespace cobalt

#endif // COBALT_EVENTS_HPP_INCLUDED
<|endoftext|>


<commit_before>/*
 * AbstractSimpleStoringParticleDataSource.cpp
 *
 * Copyright (C) 2012 by TU Dresden (CGV)
 * Alle Rechte vorbehalten.
 */

#include "stdafx.h"
#include "AbstractSimpleStoringParticleDataSource.h"
#include "param/FilePathParam.h"
#include "vislib/Log.h"

using namespace megamol::core;
using namespace megamol::core::moldyn;

/*
 * AbstractSimpleStoringParticleDataSource::AbstractSimpleStoringParticleDataSource
 */
AbstractSimpleStoringParticleDataSource::AbstractSimpleStoringParticleDataSource(void) : AbstractSimpleParticleDataSource(),
        posData(), posDataType(MultiParticleDataCall::Particles::VERTDATA_NONE),
        colData(), colDataType(MultiParticleDataCall::Particles::COLDATA_NONE),
        bbox(), cbox(), defCol(192, 192, 192, 255), defRad(0.5f), minColVal(0.0f), maxColVal(1.0f), datahash(0) {
    this->filenameSlot.ForceSetDirty();
}

/*
 * AbstractSimpleStoringParticleDataSource::~AbstractSimpleStoringParticleDataSource
 */
AbstractSimpleStoringParticleDataSource::~AbstractSimpleStoringParticleDataSource(void) {
    this->Release();
}

/*
 * AbstractSimpleStoringParticleDataSource::assertData
 */
void AbstractSimpleStoringParticleDataSource::assertData(bool needLoad) {
    if (this->filenameSlot.IsDirty()) {
        needLoad = true;
        this->filenameSlot.ResetDirty();
    }
    if (needLoad) {
        try {
            if (!this->loadData(this->filenameSlot.Param<param::FilePathParam>()->Value())) {
                throw vislib::Exception("Failed to load data from file", __FILE__, __LINE__);
            }
            this->datahash++;
        } catch(vislib::Exception ex) {
            vislib::sys::Log::DefaultLog.WriteError("Exception: %s [%s, %d] (-> %s)\n", ex.GetMsgA(), ex.GetFile(), ex.GetLine(), ex.GetStack());
        } catch(...) {
            vislib::sys::Log::DefaultLog.WriteError("Unexpected exception");
        }
    }
}

/*
 * AbstractSimpleStoringParticleDataSource::getData
 */
bool AbstractSimpleStoringParticleDataSource::getData(MultiParticleDataCall& call) {
    this->assertData();

    call.AccessBoundingBoxes().Clear();
    call.AccessBoundingBoxes().SetObjectSpaceBBox(this->bbox);
    call.AccessBoundingBoxes().SetObjectSpaceClipBox(this->cbox);

    call.SetDataHash(this->datahash);

    call.SetFrameCount(1);
    call.SetFrameID(0);

    if (this->posData.IsEmpty()) return false;

    call.SetParticleListCount(1);
    SimpleSphericalParticles &p = call.AccessParticles(0);

    SIZE_T size;
    switch (this->posDataType) {
    case SimpleSphericalParticles::VERTDATA_FLOAT_XYZ: size = sizeof(float) * 3;
    case SimpleSphericalParticles::VERTDATA_FLOAT_XYZR: size = sizeof(float) * 4;
    case SimpleSphericalParticles::VERTDATA_SHORT_XYZ: size = sizeof(unsigned short) * 3;
    default: return false;
    }

    p.SetCount(this->posData.GetSize() / size);
    p.SetColourData(this->colDataType, this->colData);
    p.SetColourMapIndexValues(this->minColVal, this->maxColVal);
    p.SetGlobalColour(this->defCol.R(), this->defCol.G(), this->defCol.B(), this->defCol.A());
    p.SetGlobalRadius(this->defRad);
    p.SetVertexData(this->posDataType, this->posData);

    call.SetUnlocker(NULL);

    return true;
}

/*
 * AbstractSimpleStoringParticleDataSource::getExtent
 */
bool AbstractSimpleStoringParticleDataSource::getExtent(MultiParticleDataCall& call) {
    this->assertData();

    call.AccessBoundingBoxes().Clear();
    call.AccessBoundingBoxes().SetObjectSpaceBBox(this->bbox);
    call.AccessBoundingBoxes().SetObjectSpaceClipBox(this->cbox);

    call.SetDataHash(this->datahash);

    call.SetFrameCount(1);
    call.SetFrameID(0);

    call.SetUnlocker(NULL);

    return !this->posData.IsEmpty();
}
<commit_msg>Ack Bug<commit_after>/*
 * AbstractSimpleStoringParticleDataSource.cpp
 *
 * Copyright (C) 2012 by TU Dresden (CGV)
 * Alle Rechte vorbehalten.
 */

#include "stdafx.h"
#include "AbstractSimpleStoringParticleDataSource.h"
#include "param/FilePathParam.h"
#include "vislib/Log.h"

using namespace megamol::core;
using namespace megamol::core::moldyn;

/*
 * AbstractSimpleStoringParticleDataSource::AbstractSimpleStoringParticleDataSource
 */
AbstractSimpleStoringParticleDataSource::AbstractSimpleStoringParticleDataSource(void) : AbstractSimpleParticleDataSource(),
        posData(), posDataType(MultiParticleDataCall::Particles::VERTDATA_NONE),
        colData(), colDataType(MultiParticleDataCall::Particles::COLDATA_NONE),
        bbox(), cbox(), defCol(192, 192, 192, 255), defRad(0.5f), minColVal(0.0f), maxColVal(1.0f), datahash(0) {
    this->filenameSlot.ForceSetDirty();
}

/*
 * AbstractSimpleStoringParticleDataSource::~AbstractSimpleStoringParticleDataSource
 */
AbstractSimpleStoringParticleDataSource::~AbstractSimpleStoringParticleDataSource(void) {
    this->Release();
}

/*
 * AbstractSimpleStoringParticleDataSource::assertData
 */
void AbstractSimpleStoringParticleDataSource::assertData(bool needLoad) {
    if (this->filenameSlot.IsDirty()) {
        needLoad = true;
        this->filenameSlot.ResetDirty();
    }
    if (needLoad) {
        try {
            if (!this->loadData(this->filenameSlot.Param<param::FilePathParam>()->Value())) {
                throw vislib::Exception("Failed to load data from file", __FILE__, __LINE__);
            }
            this->datahash++;
        } catch(vislib::Exception ex) {
            vislib::sys::Log::DefaultLog.WriteError("Exception: %s [%s, %d] (-> %s)\n", ex.GetMsgA(), ex.GetFile(), ex.GetLine(), ex.GetStack());
        } catch(...) {
            vislib::sys::Log::DefaultLog.WriteError("Unexpected exception");
        }
    }
}

/*
 * AbstractSimpleStoringParticleDataSource::getData
 */
bool AbstractSimpleStoringParticleDataSource::getData(MultiParticleDataCall& call) {
    this->assertData();

    call.AccessBoundingBoxes().Clear();
    call.AccessBoundingBoxes().SetObjectSpaceBBox(this->bbox);
    call.AccessBoundingBoxes().SetObjectSpaceClipBox(this->cbox);

    call.SetDataHash(this->datahash);

    call.SetFrameCount(1);
    call.SetFrameID(0);

    if (this->posData.IsEmpty()) return false;

    call.SetParticleListCount(1);
    SimpleSphericalParticles &p = call.AccessParticles(0);

    SIZE_T size;
    switch (this->posDataType) {
    case SimpleSphericalParticles::VERTDATA_FLOAT_XYZ: size = sizeof(float) * 3; break;
    case SimpleSphericalParticles::VERTDATA_FLOAT_XYZR: size = sizeof(float) * 4; break;
    case SimpleSphericalParticles::VERTDATA_SHORT_XYZ: size = sizeof(unsigned short) * 3; break;
    default: return false;
    }

    p.SetCount(this->posData.GetSize() / size);
    p.SetColourData(this->colDataType, this->colData);
    p.SetColourMapIndexValues(this->minColVal, this->maxColVal);
    p.SetGlobalColour(this->defCol.R(), this->defCol.G(), this->defCol.B(), this->defCol.A());
    p.SetGlobalRadius(this->defRad);
    p.SetVertexData(this->posDataType, this->posData);

    call.SetUnlocker(NULL);

    return true;
}

/*
 * AbstractSimpleStoringParticleDataSource::getExtent
 */
bool AbstractSimpleStoringParticleDataSource::getExtent(MultiParticleDataCall& call) {
    this->assertData();

    call.AccessBoundingBoxes().Clear();
    call.AccessBoundingBoxes().SetObjectSpaceBBox(this->bbox);
    call.AccessBoundingBoxes().SetObjectSpaceClipBox(this->cbox);

    call.SetDataHash(this->datahash);

    call.SetFrameCount(1);
    call.SetFrameID(0);

    call.SetUnlocker(NULL);

    return !this->posData.IsEmpty();
}
<|endoftext|>


<commit_before>#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/core/random.h>
#include <babylon/engines/scene.h>
#include <babylon/interfaces/irenderable_scene.h>
#include <babylon/lights/point_light.h>
#include <babylon/materials/standard_material.h>
#include <babylon/maths/vector3.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/instanced_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/mesh_builder.h>
#include <babylon/samples/babylon_register_sample.h>

namespace BABYLON {

class AbstractMesh;
class Mesh;
using AbstractMeshPtr = std::shared_ptr<AbstractMesh>;
using MeshPtr         = std::shared_ptr<Mesh>;

namespace Samples {

/**
 * @brief Bouncing Cube Scene.
 *
 * In this simple example, you've got :
 * - a finite world defined by the big box
 * - some random platforms inside it, built with instances
 * - a Mario player, the tiny red box
 *
 * Mario is given an initial random velocity and applied a constant gravity. You can tweak the
 * energy loss against the box walls with the variable restitution (here : 100% = 1.0)
 *
 * When Mario hits a platform coming downward (he's above the platform), he bounces back with some
 * energy loss (variable platformBounceRestitution), when he hits the platform under it, he's just
 * rejected. This is a very simple and naive physics engine because I don't even test if Mario hits
 * the platform borders here. But it is fast.
 *
 * Note that I also test all the platforms what is not performant at all (well, they aren't very
 * numerous). The use of an octree or any preselection (we know where all the obstacles are in the
 * space before the scene starts !) would be better.
 *
 * @see http://www.babylonjs-playground.com/#PBVEM#17
 */
class BouncingCubeScene : public IRenderableScene {

public:
  BouncingCubeScene(ICanvas* iCanvas)
      : IRenderableScene(iCanvas)
      , _limit{0.f}
      , _restitution{0.f}
      , _platformBounceRestitution{0.f}
      , _k{0.f}
      , _mario{nullptr}
  {
  }
  ~BouncingCubeScene() override = default;

  const char* getName() override
  {
    return "Bouncing Cube Scene";
  }
  void initializeScene(ICanvas* canvas, Scene* scene) override
  {
    scene->clearColor = Color3::Black();
    auto camera       = ArcRotateCamera::New("camera1", 0.f, 0.f, 0.f, Vector3::Zero(), scene);
    camera->setPosition(Vector3(0.f, 10.f, -500.f));
    camera->attachControl(canvas, true);

    auto pl       = PointLight::New("pl", Vector3::Zero(), scene);
    pl->diffuse   = Color3(1.f, 1.f, 1.f);
    pl->intensity = 1.f;
    pl->position  = camera->position;

    auto boxSize               = 300.f;
    auto marioSize             = 5.f;
    auto platformNb            = 25;
    auto platformHeight        = 3.f;
    auto platformMaxWidth      = 40.f;
    auto platformMaxDepth      = 20.f;
    auto platformMinSize       = 20.f;
    _gravity                   = Vector3(0.f, -0.2f, 0.f);
    _platformBounceRestitution = 0.97f;
    auto speed                 = 2.f;
    _restitution               = 0.95f;
    _limit                     = (boxSize - marioSize) * 0.5f;
    auto platformLimit         = boxSize - platformMaxWidth - 10.f;
    _velocity                  = Vector3(Math::random(), Math::random(), Math::random());
    _velocity.scaleInPlace(speed);
    auto initialVel = Vector3(0.5f, 2.f, 0.f);
    _velocity.addInPlace(initialVel);

    BoxOptions boxOptions;
    boxOptions.size            = boxSize;
    boxOptions.sideOrientation = Mesh::BACKSIDE;
    auto box                   = MeshBuilder::CreateBox("b", boxOptions, scene);
    auto boxmat                = StandardMaterial::New("boxmat", scene);
    boxmat->diffuseColor       = Color3(0.4f, 0.6f, 1.f);
    boxmat->specularColor      = Color3::Black();
    box->material              = boxmat;

    BoxOptions marioOptions;
    marioOptions.size       = marioSize;
    _mario                  = MeshBuilder::CreateBox("m", marioOptions, scene);
    auto marioMat           = StandardMaterial::New("marioMat", scene);
    marioMat->diffuseColor  = Color3::Red();
    marioMat->specularColor = Color3::Black();
    _mario->material        = marioMat;

    BoxOptions platformOptions;
    platformOptions.size       = 1.f;
    auto platform              = MeshBuilder::CreateBox("p", platformOptions, scene);
    auto platformMat           = StandardMaterial::New("platform0", scene);
    platformMat->diffuseColor  = Color3::Green();
    platformMat->specularColor = Color3::Black();
    platformMat->alpha         = 0.7f;
    platform->material         = platformMat;
    platform->position
      = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                (0.5f - Math::random()) * platformLimit);
    platform->scaling = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                                platformMinSize + Math::random() * platformMaxDepth);

    _platforms.emplace_back(platform);
    for (int i = 1; i < platformNb; ++i) {
      const auto instance = platform->createInstance("platform" + std::to_string(i));
      instance->position
        = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                  (0.5f - Math::random()) * platformLimit);
      platform->scaling
        = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                  platformMinSize + Math::random() * platformMaxDepth);
      _platforms.emplace_back(instance);
    }

    scene->registerBeforeRender([this](Scene* /*scene*/, EventState& /*es*/) -> void {
      _applyForces();
      _checkCollisions();
      _moveMario();
      _movePlatforms();
      _k += 0.001f;
    });
  }

private:
  void _applyForces();
  void _checkCollisions();
  void _moveMario();
  void _movePlatforms();

private:
  Vector3 _gravity;
  Vector3 _velocity;
  float _limit;
  float _restitution;
  float _platformBounceRestitution;
  float _k;
  MeshPtr _mario;
  std::vector<AbstractMeshPtr> _platforms;

}; // end of class BouncingCubeScene

} // end of namespace Samples
} // end of namespace BABYLON

namespace BABYLON {
namespace Samples {

void BouncingCubeScene::_applyForces()
{
  _velocity.addInPlace(_gravity);
}

void BouncingCubeScene::_checkCollisions()
{
  // Check box walls
  if (std::abs(_mario->position().x) > _limit) {
    _velocity.x *= -1.f;
    _mario->position().x = (_mario->position().x > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().y) > _limit) {
    _velocity.y *= -1.f * _restitution;
    _mario->position().y = (_mario->position().y > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().z) > _limit) {
    _velocity.z *= -1.f;
    _mario->position().z = (_mario->position().z > 0.f) ? _limit : -_limit;
  }
  // Check platforms
  size_t i = 0;
  for (auto& platform : _platforms) {
    if (_mario->intersectsMesh(*platform)) {
      // naive impact point check
      if (_mario->position().y > platform->position().y) {
        _mario->position().y = platform->position().y + platform->scaling().y * 0.5f;
        _velocity.y *= -_platformBounceRestitution;
      }
      if (_mario->position().y < platform->position().y) {
        _velocity.y *= -1.f;
      }
    }
    ++i;
  }
}

void BouncingCubeScene::_moveMario()
{
  _mario->position().addInPlace(_velocity);
}

void BouncingCubeScene::_movePlatforms()
{
  size_t i = 0;
  for (auto& platform : _platforms) {
    auto p = i % 3;
    switch (p) {
      case 0:
        platform->position().x += 0.1f * std::sin(_k * i);
        break;
      case 1:
        platform->position().y -= 0.2f * std::cos(_k * i);
        break;
      case 2:
        platform->position().z -= 0.03f * std::sin(_k * i);
        break;
    }
    ++i;
  }
}

BABYLON_REGISTER_SAMPLE("Animations", BouncingCubeScene)

} // end of namespace Samples
} // end of namespace BABYLON
<commit_msg>Using macro for forward declarations<commit_after>#include <babylon/babylon_fwd.h>
#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/core/random.h>
#include <babylon/engines/scene.h>
#include <babylon/interfaces/irenderable_scene.h>
#include <babylon/lights/point_light.h>
#include <babylon/materials/standard_material.h>
#include <babylon/maths/vector3.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/instanced_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/mesh_builder.h>
#include <babylon/samples/babylon_register_sample.h>

namespace BABYLON {

FWD_CLASS_SPTR(AbstractMesh)
FWD_CLASS_SPTR(Mesh)

namespace Samples {

/**
 * @brief Bouncing Cube Scene.
 *
 * In this simple example, you've got :
 * - a finite world defined by the big box
 * - some random platforms inside it, built with instances
 * - a Mario player, the tiny red box
 *
 * Mario is given an initial random velocity and applied a constant gravity. You can tweak the
 * energy loss against the box walls with the variable restitution (here : 100% = 1.0)
 *
 * When Mario hits a platform coming downward (he's above the platform), he bounces back with some
 * energy loss (variable platformBounceRestitution), when he hits the platform under it, he's just
 * rejected. This is a very simple and naive physics engine because I don't even test if Mario hits
 * the platform borders here. But it is fast.
 *
 * Note that I also test all the platforms what is not performant at all (well, they aren't very
 * numerous). The use of an octree or any preselection (we know where all the obstacles are in the
 * space before the scene starts !) would be better.
 *
 * @see http://www.babylonjs-playground.com/#PBVEM#17
 */
class BouncingCubeScene : public IRenderableScene {

public:
  BouncingCubeScene(ICanvas* iCanvas)
      : IRenderableScene(iCanvas)
      , _limit{0.f}
      , _restitution{0.f}
      , _platformBounceRestitution{0.f}
      , _k{0.f}
      , _mario{nullptr}
  {
  }
  ~BouncingCubeScene() override = default;

  const char* getName() override
  {
    return "Bouncing Cube Scene";
  }
  void initializeScene(ICanvas* canvas, Scene* scene) override
  {
    scene->clearColor = Color3::Black();
    auto camera       = ArcRotateCamera::New("camera1", 0.f, 0.f, 0.f, Vector3::Zero(), scene);
    camera->setPosition(Vector3(0.f, 10.f, -500.f));
    camera->attachControl(canvas, true);

    auto pl       = PointLight::New("pl", Vector3::Zero(), scene);
    pl->diffuse   = Color3(1.f, 1.f, 1.f);
    pl->intensity = 1.f;
    pl->position  = camera->position;

    auto boxSize               = 300.f;
    auto marioSize             = 5.f;
    auto platformNb            = 25;
    auto platformHeight        = 3.f;
    auto platformMaxWidth      = 40.f;
    auto platformMaxDepth      = 20.f;
    auto platformMinSize       = 20.f;
    _gravity                   = Vector3(0.f, -0.2f, 0.f);
    _platformBounceRestitution = 0.97f;
    auto speed                 = 2.f;
    _restitution               = 0.95f;
    _limit                     = (boxSize - marioSize) * 0.5f;
    auto platformLimit         = boxSize - platformMaxWidth - 10.f;
    _velocity                  = Vector3(Math::random(), Math::random(), Math::random());
    _velocity.scaleInPlace(speed);
    auto initialVel = Vector3(0.5f, 2.f, 0.f);
    _velocity.addInPlace(initialVel);

    BoxOptions boxOptions;
    boxOptions.size            = boxSize;
    boxOptions.sideOrientation = Mesh::BACKSIDE;
    auto box                   = MeshBuilder::CreateBox("b", boxOptions, scene);
    auto boxmat                = StandardMaterial::New("boxmat", scene);
    boxmat->diffuseColor       = Color3(0.4f, 0.6f, 1.f);
    boxmat->specularColor      = Color3::Black();
    box->material              = boxmat;

    BoxOptions marioOptions;
    marioOptions.size       = marioSize;
    _mario                  = MeshBuilder::CreateBox("m", marioOptions, scene);
    auto marioMat           = StandardMaterial::New("marioMat", scene);
    marioMat->diffuseColor  = Color3::Red();
    marioMat->specularColor = Color3::Black();
    _mario->material        = marioMat;

    BoxOptions platformOptions;
    platformOptions.size       = 1.f;
    auto platform              = MeshBuilder::CreateBox("p", platformOptions, scene);
    auto platformMat           = StandardMaterial::New("platform0", scene);
    platformMat->diffuseColor  = Color3::Green();
    platformMat->specularColor = Color3::Black();
    platformMat->alpha         = 0.7f;
    platform->material         = platformMat;
    platform->position
      = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                (0.5f - Math::random()) * platformLimit);
    platform->scaling = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                                platformMinSize + Math::random() * platformMaxDepth);

    _platforms.emplace_back(platform);
    for (int i = 1; i < platformNb; ++i) {
      const auto instance = platform->createInstance("platform" + std::to_string(i));
      instance->position
        = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                  (0.5f - Math::random()) * platformLimit);
      platform->scaling
        = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                  platformMinSize + Math::random() * platformMaxDepth);
      _platforms.emplace_back(instance);
    }

    scene->registerBeforeRender([this](Scene* /*scene*/, EventState& /*es*/) -> void {
      _applyForces();
      _checkCollisions();
      _moveMario();
      _movePlatforms();
      _k += 0.001f;
    });
  }

private:
  void _applyForces();
  void _checkCollisions();
  void _moveMario();
  void _movePlatforms();

private:
  Vector3 _gravity;
  Vector3 _velocity;
  float _limit;
  float _restitution;
  float _platformBounceRestitution;
  float _k;
  MeshPtr _mario;
  std::vector<AbstractMeshPtr> _platforms;

}; // end of class BouncingCubeScene

} // end of namespace Samples
} // end of namespace BABYLON

namespace BABYLON {
namespace Samples {

void BouncingCubeScene::_applyForces()
{
  _velocity.addInPlace(_gravity);
}

void BouncingCubeScene::_checkCollisions()
{
  // Check box walls
  if (std::abs(_mario->position().x) > _limit) {
    _velocity.x *= -1.f;
    _mario->position().x = (_mario->position().x > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().y) > _limit) {
    _velocity.y *= -1.f * _restitution;
    _mario->position().y = (_mario->position().y > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().z) > _limit) {
    _velocity.z *= -1.f;
    _mario->position().z = (_mario->position().z > 0.f) ? _limit : -_limit;
  }
  // Check platforms
  size_t i = 0;
  for (auto& platform : _platforms) {
    if (_mario->intersectsMesh(*platform)) {
      // naive impact point check
      if (_mario->position().y > platform->position().y) {
        _mario->position().y = platform->position().y + platform->scaling().y * 0.5f;
        _velocity.y *= -_platformBounceRestitution;
      }
      if (_mario->position().y < platform->position().y) {
        _velocity.y *= -1.f;
      }
    }
    ++i;
  }
}

void BouncingCubeScene::_moveMario()
{
  _mario->position().addInPlace(_velocity);
}

void BouncingCubeScene::_movePlatforms()
{
  size_t i = 0;
  for (auto& platform : _platforms) {
    auto p = i % 3;
    switch (p) {
      case 0:
        platform->position().x += 0.1f * std::sin(_k * i);
        break;
      case 1:
        platform->position().y -= 0.2f * std::cos(_k * i);
        break;
      case 2:
        platform->position().z -= 0.03f * std::sin(_k * i);
        break;
    }
    ++i;
  }
}

BABYLON_REGISTER_SAMPLE("Animations", BouncingCubeScene)

} // end of namespace Samples
} // end of namespace BABYLON
<|endoftext|>


<commit_before>#include <limits>
#include <algorithm>
#include <array>
#include <iomanip>
#include <curl/curl.h>
#include <memory>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");
const std::string update_check("");

const std::string file_checksum(const std::string &path);

size_t writefunction(const char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string *s = static_cast<std::string *>(userdata);
    s->append(ptr, size * nmemb);
    return size * nmemb;
}

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch()
        {
            std::cout << "Statting target " << name() << "...";
            std::string path;
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                auto elems = split(name(), '/');
                for (size_t i = 0, k = elems.size(); i < k; ++i)
                {
                    const std::string &s(elems[i]);
                    if (s.size() && s != ".")
                    {
                        path.append((i > 0 ? "/" : "") + s);
                        // i indicates a directory.
                        if (i < k - 1)
                        {
                            auto status = mkdir(path.c_str(), S_IRWXU);
                            if (status == -1)
                            {
                                std::error_code err(errno, std::generic_category());
                                if (err != std::errc::file_exists)
                                {
                                    std::cout << "error making dir: "
                                        << path << ": "
                                        << err.message() << std::endl;
                                }
                            }
                        }
                    }
                }
                fs.open(path, std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << path << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }
        Status status()
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();
            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch()
        {
            std::string s;
            std::shared_ptr<CURL *> phandle =
                std::make_shared<CURL *>(curl_easy_init());
            std::string url(patch_dir + name());
            curl_easy_setopt(*phandle, CURLOPT_URL, url.c_str());
            curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
            curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &s);
            //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
            curl_easy_perform(*phandle);
            curl_easy_cleanup(*phandle);
            phandle.reset();
            std::ofstream ofs(name());
            if (ofs.good())
            {
                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

class CurlGlobalInit
{
    public:
        CurlGlobalInit()
        {
            curl_global_init(CURL_GLOBAL_ALL);
        }

        ~CurlGlobalInit()
        {
            curl_global_cleanup();
        }
};

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */

    return calcsum.str();
}

struct Options
{
    bool checksum(const std::string &val)
    {
        return val == "checksum";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = tolower(c);
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

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

    const std::string update_check("https://raw.github.com/commonquail/efulauncher/updatecheck/versioncheck");
    std::string fetch;
    std::shared_ptr<CURL *> phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, update_check.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);

    Options opts;
    std::vector<std::string> lines(split(fetch, '\n'));
    fetch.clear();
    for (auto beg = std::begin(lines), end = std::end(lines);
            beg != end; ++beg)
    {
        auto keyvals(split(*beg, '='));
        if (opts.checksum(keyvals[0]))
        {
            const std::string checksum_test(keyvals[keyvals.size() - 1]);
            if (checksum_test != file_checksum(argv[0]))
            {
                std::cout << "A new version of the launcher is available."\
                    " Would you like to download it (y/n)?" << std::endl;
                bool download(confirm());
                if (!download)
                {
                    std::cout << "It is strongly recommended to always use the latest launcher."\
                        " Would you like to download it (y/n)?" << std::endl;
                    download = confirm();
                }
                if (download)
                {
                    // Download.
                    std::cout << "Downloading new launcher..." << std::endl;
                    std::cout << "Done." << std::endl;
                }
            }
        }
    }

    phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, listing.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);
    phandle.reset();

    lines = split(fetch, '\n');
    std::vector<Target> new_targets, old_targets;
    for (auto beg = std::begin(lines), end = std::end(lines);
            beg != end; ++beg)
    {
        auto data(split(*beg, '@'));
        Target t(data[0], data[data.size() - 1]);
        auto status = t.status();
        if (status == Target::Status::Nonexistent)
        {
            new_targets.push_back(std::move(t));
        }
        else if (status == Target::Status::Outdated)
        {
            old_targets.push_back(std::move(t));
        }
    }
    if (new_targets.size())
    {
        std::cout << "New targets: " << new_targets.size() << std::endl;
        for (auto &t : new_targets)
        {
            std::cout << "- " << t.name() << std::endl;
        }
    }
    else
    {
        std::cout << "No new targets." << std::endl;
    }

    if (old_targets.size())
    {
        std::cout << "Outdated targets: " << old_targets.size() << std::endl;
        for (auto &t : old_targets)
        {
            std::cout << "- " << t.name() << std::endl;
        }
    }
    else
    {
        std::cout << "No targets out of date." << std::endl;
    }

    for (auto &t : new_targets)
    {
        t.fetch();
    }
    for (auto &t : old_targets)
    {
        t.fetch();
    }

    return 0;
}
<commit_msg>Don't call fetch() if DEBUG is defined.<commit_after>#include <limits>
#include <algorithm>
#include <array>
#include <iomanip>
#include <curl/curl.h>
#include <memory>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");
const std::string update_check("");

const std::string file_checksum(const std::string &path);

size_t writefunction(const char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string *s = static_cast<std::string *>(userdata);
    s->append(ptr, size * nmemb);
    return size * nmemb;
}

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch()
        {
            std::cout << "Statting target " << name() << "...";
            std::string path;
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                auto elems = split(name(), '/');
                for (size_t i = 0, k = elems.size(); i < k; ++i)
                {
                    const std::string &s(elems[i]);
                    if (s.size() && s != ".")
                    {
                        path.append((i > 0 ? "/" : "") + s);
                        // i indicates a directory.
                        if (i < k - 1)
                        {
                            auto status = mkdir(path.c_str(), S_IRWXU);
                            if (status == -1)
                            {
                                std::error_code err(errno, std::generic_category());
                                if (err != std::errc::file_exists)
                                {
                                    std::cout << "error making dir: "
                                        << path << ": "
                                        << err.message() << std::endl;
                                }
                            }
                        }
                    }
                }
                fs.open(path, std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << path << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }
        Status status()
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();
            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch()
        {
            std::string s;
            std::shared_ptr<CURL *> phandle =
                std::make_shared<CURL *>(curl_easy_init());
            std::string url(patch_dir + name());
            curl_easy_setopt(*phandle, CURLOPT_URL, url.c_str());
            curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
            curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &s);
            //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
            curl_easy_perform(*phandle);
            curl_easy_cleanup(*phandle);
            phandle.reset();
            std::ofstream ofs(name());
            if (ofs.good())
            {
                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

class CurlGlobalInit
{
    public:
        CurlGlobalInit()
        {
            curl_global_init(CURL_GLOBAL_ALL);
        }

        ~CurlGlobalInit()
        {
            curl_global_cleanup();
        }
};

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */

    return calcsum.str();
}

struct Options
{
    bool checksum(const std::string &val)
    {
        return val == "checksum";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = tolower(c);
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

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

    const std::string update_check("https://raw.github.com/commonquail/efulauncher/updatecheck/versioncheck");
    std::string fetch;
    std::shared_ptr<CURL *> phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, update_check.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);

    Options opts;
    std::vector<std::string> lines(split(fetch, '\n'));
    fetch.clear();
    for (auto beg = std::begin(lines), end = std::end(lines);
            beg != end; ++beg)
    {
        auto keyvals(split(*beg, '='));
        if (opts.checksum(keyvals[0]))
        {
            const std::string checksum_test(keyvals[keyvals.size() - 1]);
            if (checksum_test != file_checksum(argv[0]))
            {
                std::cout << "A new version of the launcher is available."\
                    " Would you like to download it (y/n)?" << std::endl;
                bool download(confirm());
                if (!download)
                {
                    std::cout << "It is strongly recommended to always use the latest launcher."\
                        " Would you like to download it (y/n)?" << std::endl;
                    download = confirm();
                }
                if (download)
                {
                    // Download.
                    std::cout << "Downloading new launcher..." << std::endl;
                    std::cout << "Done." << std::endl;
                }
            }
        }
    }

    phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, listing.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);
    phandle.reset();

    lines = split(fetch, '\n');
    std::vector<Target> new_targets, old_targets;
    for (auto beg = std::begin(lines), end = std::end(lines);
            beg != end; ++beg)
    {
        auto data(split(*beg, '@'));
        Target t(data[0], data[data.size() - 1]);
        auto status = t.status();
        if (status == Target::Status::Nonexistent)
        {
            new_targets.push_back(std::move(t));
        }
        else if (status == Target::Status::Outdated)
        {
            old_targets.push_back(std::move(t));
        }
    }
    if (new_targets.size())
    {
        std::cout << "New targets: " << new_targets.size() << std::endl;
        for (auto &t : new_targets)
        {
            std::cout << "- " << t.name() << std::endl;
        }
    }
    else
    {
        std::cout << "No new targets." << std::endl;
    }

    if (old_targets.size())
    {
        std::cout << "Outdated targets: " << old_targets.size() << std::endl;
        for (auto &t : old_targets)
        {
            std::cout << "- " << t.name() << std::endl;
        }
    }
    else
    {
        std::cout << "No targets out of date." << std::endl;
    }

#ifndef DEBUG
    for (auto &t : new_targets)
    {
        t.fetch();
    }
    for (auto &t : old_targets)
    {
        t.fetch();
    }
#endif

    return 0;
}
<|endoftext|>


<commit_before>/*
src/main.cpp

Created by Jon Stewart on 2010-01-04.
Copyright (c) 2010 Lightbox Technologies, Inc.
*/

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>

#include "walkers.h"

#if defined(__WIN32__) || defined(_WIN32_) || defined(__WIN32) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS__) || defined(__TOS_WIN__)
  #include <cstdio>
  #include <fcntl.h>
  void std_binary_io() {
    _setmode( _fileno( stdin  ), _O_BINARY );
    _setmode( _fileno( stdout ), _O_BINARY );
    _setmode( _fileno( stderr ), _O_BINARY );
    std::cin.sync_with_stdio();
  }
#else
  void std_binary_io() { }
#endif

namespace po = boost::program_options;

void printHelp(const po::options_description& desc) {
  std::cout << "fsrip, Copyright (c) 2010-2012, Lightbox Technologies, Inc." << std::endl;
  std::cout << "Built " << __DATE__ << std::endl;
  std::cout << "TSK version is " << tsk_version_get_str() << std::endl;
  std::cout << desc << std::endl;
}

std::shared_ptr<LbtTskAuto> createVisitor(const std::string& cmd, std::ostream& out, const std::vector<std::string>& segments) {
  if (cmd == "dumpimg") {
    return std::shared_ptr<LbtTskAuto>(new ImageDumper(out));
  }
  else if (cmd == "dumpfs") {
    return std::shared_ptr<LbtTskAuto>(new MetadataWriter(out));
  }
  else if (cmd == "dumpfiles") {
    return std::shared_ptr<LbtTskAuto>(new FileWriter(out));
  }
  else {
    return std::shared_ptr<LbtTskAuto>();
  }
}

int makeVolMode(const std::string& mode) {
  if (mode == "none") {
    return 0;
  }
  else if (mode == "unallocated") {
    return TSK_VS_PART_FLAG_UNALLOC;
  }
  else if (mode == "allocated") {
    return TSK_VS_PART_FLAG_ALLOC;
  }
  else if (mode == "metadata") {
    return TSK_VS_PART_FLAG_META;
  }
  else if (mode == "all") {
    return TSK_VS_PART_FLAG_UNALLOC | TSK_VS_PART_FLAG_ALLOC | TSK_VS_PART_FLAG_META;
  }
  else {
    return -1; // shouldn't happen
  }
}

int main(int argc, char *argv[]) {
  std::string ucMode,
              volMode;

  po::options_description desc("Allowed Options");
  po::positional_options_description posOpts;
  posOpts.add("command", 1);
  posOpts.add("ev-files", -1);
  desc.add_options()
    ("help", "produce help message")
    ("command", po::value< std::string >(), "command to perform [dumpimg|dumpfs|dumpfiles]")
    ("overview-file", po::value< std::string >(), "output disk overview information")
    ("unallocated", po::value< std::string >(&ucMode)->default_value("none"), "how to handle unallocated [none|fragment|block]")
    ("volume-entries", po::value< std::string >(&volMode)->default_value("none"), "output metadata entries for volumes [none|unallocated|allocated|metadata|all")
    ("ev-files", po::value< std::vector< std::string > >(), "evidence files");

  po::variables_map vm;
  try {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(posOpts).run(), vm);
    po::notify(vm);

    std::shared_ptr<LbtTskAuto> walker;

    std::vector< std::string > imgSegs;
    if (vm.count("ev-files")) {
      imgSegs = vm["ev-files"].as< std::vector< std::string > >();
    }
    if (vm.count("help")) {
      printHelp(desc);
    }
    else if (vm.count("command") && vm.count("ev-files") && (walker = createVisitor(vm["command"].as<std::string>(), std::cout, imgSegs))) {
      std_binary_io();

      boost::scoped_array< const char* >  segments(new const char*[imgSegs.size()]);
      for (unsigned int i = 0; i < imgSegs.size(); ++i) {
        segments[i] = imgSegs[i].c_str();
      }
      if (0 == walker->openImageUtf8(imgSegs.size(), segments.get(), TSK_IMG_TYPE_DETECT, 0)) {
        if (vm.count("overview-file")) {
          std::ofstream file(vm["overview-file"].as<std::string>().c_str(), std::ios::out);
          file << *(walker->getImage(imgSegs));
          file.close();
        }

        walker->setVolFilterFlags((TSK_VS_PART_FLAG_ENUM)(TSK_VS_PART_FLAG_ALLOC | TSK_VS_PART_FLAG_UNALLOC | TSK_VS_PART_FLAG_META));
        walker->setFileFilterFlags((TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_ALLOC));
        walker->setVolMetadataMode(makeVolMode(volMode));
        if (ucMode == "fragment") {
          walker->setUnallocatedMode(LbtTskAuto::FRAGMENT);
        }
        else if (ucMode == "block") {
          walker->setUnallocatedMode(LbtTskAuto::BLOCK);
        }
        else {
          walker->setUnallocatedMode(LbtTskAuto::NONE);
        }
        if (0 == walker->start()) {
          walker->startUnallocated();
          walker->finishWalk();
          return 0;
        }
        else {
          std::cout.flush();
          std::cerr << "Had an error parsing filesystem" << std::endl;
          for (auto& err: walker->getErrorList()) {
            std::cerr << err.msg1 << " " << err.msg2 << std::endl;
          }
        }
      }
      else {
        std::cerr << "Had an error opening the evidence file" << std::endl;
        for (unsigned int i = 0; i < imgSegs.size(); ++i) {
          std::cerr << " ** seg[" << i << "] = " << imgSegs[i] << std::endl;
        }
        return 1;
      }
    }
    else {
      std::cerr << "Error: did not understand arguments\n\n";
      printHelp(desc);
      return 1;
    }
  }
  catch (std::exception& err) {
    std::cerr << "Error: " << err.what() << "\n\n";
    printHelp(desc);
    return 1;
  }
  return 0;
}
<commit_msg>Add a few as-yet-unused options<commit_after>/*
src/main.cpp

Created by Jon Stewart on 2010-01-04.
Copyright (c) 2010 Lightbox Technologies, Inc.
*/

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>

#include "walkers.h"

#if defined(__WIN32__) || defined(_WIN32_) || defined(__WIN32) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS__) || defined(__TOS_WIN__)
  #include <cstdio>
  #include <fcntl.h>
  void std_binary_io() {
    _setmode( _fileno( stdin  ), _O_BINARY );
    _setmode( _fileno( stdout ), _O_BINARY );
    _setmode( _fileno( stderr ), _O_BINARY );
    std::cin.sync_with_stdio();
  }
#else
  void std_binary_io() { }
#endif

namespace po = boost::program_options;

void printHelp(const po::options_description& desc) {
  std::cout << "fsrip, Copyright (c) 2010-2012, Lightbox Technologies, Inc." << std::endl;
  std::cout << "Built " << __DATE__ << std::endl;
  std::cout << "TSK version is " << tsk_version_get_str() << std::endl;
  std::cout << desc << std::endl;
}

std::shared_ptr<LbtTskAuto> createVisitor(const std::string& cmd, std::ostream& out, const std::vector<std::string>& segments) {
  if (cmd == "dumpimg") {
    return std::shared_ptr<LbtTskAuto>(new ImageDumper(out));
  }
  else if (cmd == "dumpfs") {
    return std::shared_ptr<LbtTskAuto>(new MetadataWriter(out));
  }
  else if (cmd == "dumpfiles") {
    return std::shared_ptr<LbtTskAuto>(new FileWriter(out));
  }
  else {
    return std::shared_ptr<LbtTskAuto>();
  }
}

int makeVolMode(const std::string& mode) {
  if (mode == "none") {
    return 0;
  }
  else if (mode == "unallocated") {
    return TSK_VS_PART_FLAG_UNALLOC;
  }
  else if (mode == "allocated") {
    return TSK_VS_PART_FLAG_ALLOC;
  }
  else if (mode == "metadata") {
    return TSK_VS_PART_FLAG_META;
  }
  else if (mode == "all") {
    return TSK_VS_PART_FLAG_UNALLOC | TSK_VS_PART_FLAG_ALLOC | TSK_VS_PART_FLAG_META;
  }
  else {
    return -1; // shouldn't happen
  }
}

int main(int argc, char *argv[]) {
  std::string ucMode,
              volMode,
              inodeMapFile,
              diskMapFile;

  po::options_description desc("Allowed Options");
  po::positional_options_description posOpts;
  posOpts.add("command", 1);
  posOpts.add("ev-files", -1);
  desc.add_options()
    ("help", "produce help message")
    ("command", po::value< std::string >(), "command to perform [dumpimg|dumpfs|dumpfiles]")
    ("overview-file", po::value< std::string >(), "output disk overview information")
    ("unallocated", po::value< std::string >(&ucMode)->default_value("none"), "how to handle unallocated [none|fragment|block]")
    ("volume-entries", po::value< std::string >(&volMode)->default_value("none"), "output metadata entries for volumes [none|unallocated|allocated|metadata|all")
    ("ev-files", po::value< std::vector< std::string > >(), "evidence files")
    ("inode-map-file", po::value<std::string>(&inodeMapFile)->default_value(""), "optional file to output containing directory entry to inode map")
    ("disk-map-file", po::value<std::string>(&diskMapFile)->default_value(""), "optional file to output containing disk data to inode map");

  po::variables_map vm;
  try {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(posOpts).run(), vm);
    po::notify(vm);

    std::shared_ptr<LbtTskAuto> walker;

    std::vector< std::string > imgSegs;
    if (vm.count("ev-files")) {
      imgSegs = vm["ev-files"].as< std::vector< std::string > >();
    }
    if (vm.count("help")) {
      printHelp(desc);
    }
    else if (vm.count("command") && vm.count("ev-files") && (walker = createVisitor(vm["command"].as<std::string>(), std::cout, imgSegs))) {
      std_binary_io();

      boost::scoped_array< const char* >  segments(new const char*[imgSegs.size()]);
      for (unsigned int i = 0; i < imgSegs.size(); ++i) {
        segments[i] = imgSegs[i].c_str();
      }
      if (0 == walker->openImageUtf8(imgSegs.size(), segments.get(), TSK_IMG_TYPE_DETECT, 0)) {
        if (vm.count("overview-file")) {
          std::ofstream file(vm["overview-file"].as<std::string>().c_str(), std::ios::out);
          file << *(walker->getImage(imgSegs));
          file.close();
        }

        walker->setVolFilterFlags((TSK_VS_PART_FLAG_ENUM)(TSK_VS_PART_FLAG_ALLOC | TSK_VS_PART_FLAG_UNALLOC | TSK_VS_PART_FLAG_META));
        walker->setFileFilterFlags((TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_ALLOC));
        walker->setVolMetadataMode(makeVolMode(volMode));
        if (ucMode == "fragment") {
          walker->setUnallocatedMode(LbtTskAuto::FRAGMENT);
        }
        else if (ucMode == "block") {
          walker->setUnallocatedMode(LbtTskAuto::BLOCK);
        }
        else {
          walker->setUnallocatedMode(LbtTskAuto::NONE);
        }
        if (0 == walker->start()) {
          walker->startUnallocated();
          walker->finishWalk();
          return 0;
        }
        else {
          std::cout.flush();
          std::cerr << "Had an error parsing filesystem" << std::endl;
          for (auto& err: walker->getErrorList()) {
            std::cerr << err.msg1 << " " << err.msg2 << std::endl;
          }
        }
      }
      else {
        std::cerr << "Had an error opening the evidence file" << std::endl;
        for (unsigned int i = 0; i < imgSegs.size(); ++i) {
          std::cerr << " ** seg[" << i << "] = " << imgSegs[i] << std::endl;
        }
        return 1;
      }
    }
    else {
      std::cerr << "Error: did not understand arguments\n\n";
      printHelp(desc);
      return 1;
    }
  }
  catch (std::exception& err) {
    std::cerr << "Error: " << err.what() << "\n\n";
    printHelp(desc);
    return 1;
  }
  return 0;
}
<|endoftext|>