diff --git a/README.md b/README.md index 5eca845..e0fb334 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ The following libraries are needed: - **[zlib][]** (tested with version 1.2.7). - **[PhysFS][]** (tested with version 2.0.3). +- **[ssig][]**: My own library for signals (Boost.Signal is too slow). The only compiler throughoutly tested is **[MSVC 11][]**, but once upon a time the source code and `CMakeLists.txt` were adjusted to also work with g++ 4.7.2. @@ -38,9 +39,9 @@ The build system used is **[CMake][]** in a recent 2.8.x version. Especially on Windows, make sure to set any environment variables neccessary to let CMake find the librarys are set correctly: `SFML_ROOT`, `BOOST_ROOT`, -`LUA_DIR`, `LUABIND_DIR`, `PHYSFSDIR`. zlib does not look at any environment -variables but only the `ZLIB_ROOT` CMake variable: See the second point in the -next section for how to set it. +`LUA_DIR`, `LUABIND_DIR`, `PHYSFSDIR`, `SSIG_DIR`. zlib does not look at any +environment variables but only the `ZLIB_ROOT` CMake variable: See the second +option in the [`Find*.cmake`](#setcmakevar) subsection for how to set it. As an alternative to setting the variables you can also install the libraries to the (CMake) standard locations or add the containing directories to @@ -52,26 +53,30 @@ to the (CMake) standard locations or add the containing directories to [Luabind]: http://www.rasterbar.com/products/luabind.html [zlib]: http://www.zlib.net/ [PhysFS]: http://icculus.org/physfs/ +[ssig]: https://github.com/Oberon00/ssig [MSVC 11]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-for-windows-desktop#product-express-desktop [CMake]: http://www.cmake.org/ ### `Find*.cmake` ### The `CMakeLists.txt` for jd call `find_package()` with some libraries where -the corresponding `Find*.cmake` is not built in, namely `Lua52`, `Luabind` and -`SFML`. The latter is included with SFML itself and the first two are both -contained in my Luabind fork, linked above. To make CMake find them you have -two options: +the corresponding `Find*.cmake` is not built in: + +* `FindLua52.cmake` and `FindLuabind.cmake` are contained in my Luabind fork + linked above. +* `FindSFML.cmake` and `Findssig.cmake` are contained in their own libraries. + +To make CMake find them you have two options: - Copy the files to your CMake installation's module directory. This is the directory where e.g. the `AddFileDependencies.cmake` module is located. It usually lies in `/share/cmake-2.8/Modules`, where `` is the installation directory on Windows (usually `C:\Program Files (x86)\CMake 2.8`) and usually simply `/usr` on Linux. -- Specify the directories where the files are located as a semicolon `;` - separated list in the `CMAKE_MODULE_PATH` CMake cache variable: *Add entry*, - type string in the Windows GUI; or `-DCMAKE_MODULE_PATH=` on the - command line. +- Specify the directories where the files are located + as a semicolon `;` separated list in the `CMAKE_MODULE_PATH` CMake cache + variable: *Add entry*, type string in the Windows GUI; + or `-DCMAKE_MODULE_PATH=` on the command line. > Jade Engine -- Copyright (c) Christian Neumüller 2012--2013 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 770e26c..8c2d2b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,8 +129,6 @@ source_group("Collisions" FILES ${COLLISION_SOURCES} ${COLLISION_HEADERS}) set(JD_HEADERS encoding.hpp - ssig.hpp - ssig_template.hpp MapInfo.hpp exceptions.hpp sfKeyCodes.hpp @@ -212,6 +210,7 @@ find_package(PhysFS REQUIRED) find_package(ZLIB REQUIRED) find_package(Lua52 REQUIRED) find_package(Luabind REQUIRED) +find_package(ssig REQUIRED) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) @@ -226,7 +225,8 @@ include_directories( ${LUABIND_INCLUDE_DIRS} ${PHYSFS_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS}) + ${Boost_INCLUDE_DIRS} + ${SSIG_INCLUDE_DIRS}) add_executable(jd WIN32 ${JD_HEADERS} ${JD_SOURCES}) set_target_properties(jd PROPERTIES COMPILE_DEFINITIONS "${COMP_DEFS}") target_link_libraries(jd diff --git a/src/comp/PositionComponent.hpp b/src/comp/PositionComponent.hpp index a0cfab6..cfc0848 100644 --- a/src/comp/PositionComponent.hpp +++ b/src/comp/PositionComponent.hpp @@ -7,9 +7,8 @@ #include "compsys/Component.hpp" -#include "ssig.hpp" - #include +#include class Entity; diff --git a/src/comp/RectCollisionComponent.hpp b/src/comp/RectCollisionComponent.hpp index 3d1f980..03990cd 100644 --- a/src/comp/RectCollisionComponent.hpp +++ b/src/comp/RectCollisionComponent.hpp @@ -8,9 +8,9 @@ #include "compsys/Component.hpp" #include "compsys/Entity.hpp" -#include "ssig.hpp" #include +#include #include diff --git a/src/comp/TileCollisionComponent.hpp b/src/comp/TileCollisionComponent.hpp index ff567be..c1f1300 100644 --- a/src/comp/TileCollisionComponent.hpp +++ b/src/comp/TileCollisionComponent.hpp @@ -7,11 +7,11 @@ #include "compsys/Component.hpp" -#include "ssig.hpp" #include "WeakRef.hpp" #include #include +#include class TileCollideableInfo; @@ -49,7 +49,7 @@ class TileCollisionComponent: public Component { void on_tilePositionChanged( sf::Vector3 oldPos, sf::Vector3 newPos); - ScopedConnection< + ssig::ScopedConnection< void(sf::Vector3, sf::Vector3) > m_con_positionChanged; WeakRef m_tileinfo; diff --git a/src/comp/TilePositionComponent.hpp b/src/comp/TilePositionComponent.hpp index 1a394b5..5c1b7f2 100644 --- a/src/comp/TilePositionComponent.hpp +++ b/src/comp/TilePositionComponent.hpp @@ -7,10 +7,10 @@ #include "compsys/Component.hpp" -#include "ssig.hpp" - #include #include +#include + #include @@ -38,7 +38,7 @@ class TilePositionComponent: public Component { void on_positionChanged( sf::FloatRect const& oldRect, sf::FloatRect const& newRect); - ScopedConnection + ssig::ScopedConnection m_con_positionChanged; Vector3u m_tilePosition; jd::Tilemap const& m_tilemap; diff --git a/src/compsys/BasicMetaComponent.hpp b/src/compsys/BasicMetaComponent.hpp index 7d05fc7..ca9e805 100644 --- a/src/compsys/BasicMetaComponent.hpp +++ b/src/compsys/BasicMetaComponent.hpp @@ -28,13 +28,14 @@ class BasicMetaComponent: public MetaComponent { }; #define JD_EVT_METACOMPONENT(c, bc) \ - namespace { \ - class c##Meta: public bc { \ - public: \ - virtual ConnectionBase* connectEvent(lua_State*, \ - Component*, \ - std::string const& name) const; \ - }; \ + namespace { \ + class c##Meta: public bc { \ + public: \ + virtual ssig::ConnectionBase* connectEvent( \ + lua_State*, \ + Component*, \ + std::string const& name) const; \ + }; \ } // anonymous namespace diff --git a/src/compsys/MetaComponent.cpp b/src/compsys/MetaComponent.cpp index 3bd572a..e941669 100644 --- a/src/compsys/MetaComponent.cpp +++ b/src/compsys/MetaComponent.cpp @@ -9,7 +9,6 @@ #include "Entity.hpp" #include "Logfile.hpp" #include "luaUtils.hpp" -#include "ssig.hpp" #include "svc/ServiceLocator.hpp" #include "svc/LuaVm.hpp" @@ -18,6 +17,7 @@ #include #include #include +#include #include @@ -51,14 +51,14 @@ static std::ostream& operator<< (std::ostream& os, Component const& c) return os << "jd.Component (" << c.metaComponent().name() << " @" << &c << ')'; } -static ConnectionBase* connectEvent( +static ssig::ConnectionBase* connectEvent( lua_State* L, Component& sender, std::string const& eventname, luabind::object const& receiver) { receiver.push(L); - ConnectionBase* result = sender.metaComponent().connectEvent( + ssig::ConnectionBase* result = sender.metaComponent().connectEvent( L, &sender, eventname); lua_pop(L, 1); if (!result) @@ -117,7 +117,7 @@ class wrap_Component: public Component, public luabind::wrap_base { MetaComponent const* m_metaComponent; }; -class wrap_ConnectionBase: public ConnectionBase, public luabind::wrap_base { +class wrap_ConnectionBase: public ssig::ConnectionBase, public luabind::wrap_base { public: virtual void disconnect() { call("disconnect"); } virtual bool isConnected() const { return call("getIsConnected"); } @@ -148,11 +148,11 @@ static void init(LuaVm& vm) .LHISREFVALID2(Component), def("registerComponent", ®isterMetaComponent), def("connect", &connectEvent, adopt(result)), - class_("ConnectionBase") + class_("ConnectionBase") .def(constructor<>()) - .def("disconnect", &ConnectionBase::disconnect) - .def("getIsConnected", &ConnectionBase::isConnected) - .property("isConnected", &ConnectionBase::isConnected) + .def("disconnect", &ssig::ConnectionBase::disconnect) + .def("getIsConnected", &ssig::ConnectionBase::isConnected) + .property("isConnected", &ssig::ConnectionBase::isConnected) ]; lua_getglobal(vm.L(), "jd"); @@ -204,12 +204,12 @@ void LuaMetaComponent::castDown(lua_State* L, Component* c) const o.push(L); } -ConnectionBase* LuaMetaComponent::connectEvent(Component* c, std::string const& name) const +ssig::ConnectionBase* LuaMetaComponent::connectEvent(Component* c, std::string const& name) const { using namespace luabind; object receiver(from_stack(m_L, -1)); object callback = globals(m_L)[jd::moduleName]["callback_connectLuaEvent"]; if (type(callback) != LUA_TFUNCTION) throw std::runtime_error("no callback for event connection defined (must be a plain function)"); - return object_cast(callback(c, name, receiver)[adopt(result)]); + return object_cast(callback(c, name, receiver)[adopt(result)]); } diff --git a/src/compsys/MetaComponent.hpp b/src/compsys/MetaComponent.hpp index 2ddc11f..515a12d 100644 --- a/src/compsys/MetaComponent.hpp +++ b/src/compsys/MetaComponent.hpp @@ -13,7 +13,7 @@ struct lua_State; -class ConnectionBase; +namespace ssig { class ConnectionBase; } class Component; class InvalidMetaComponentName: public std::runtime_error { @@ -36,7 +36,7 @@ class InvalidMetaComponentName: public std::runtime_error { } // receiver is on top of stack; return value disconnects automatically on deletion - virtual ConnectionBase* connectEvent(lua_State*, Component*, std::string const& name) const + virtual ssig::ConnectionBase* connectEvent(lua_State*, Component*, std::string const& name) const { (void)name; return nullptr; @@ -58,7 +58,7 @@ class LuaMetaComponent: public MetaComponent { virtual std::string const& name() const; virtual void castDown(lua_State* L, Component* c) const override; - virtual ConnectionBase* connectEvent(Component* c, std::string const& name) const; + virtual ssig::ConnectionBase* connectEvent(Component* c, std::string const& name) const; private: lua_State* m_L; diff --git a/src/luaexport/LuaEventHelpers.hpp b/src/luaexport/LuaEventHelpers.hpp index 0619f9b..0e0dfe0 100644 --- a/src/luaexport/LuaEventHelpers.hpp +++ b/src/luaexport/LuaEventHelpers.hpp @@ -6,9 +6,9 @@ #define LUA_EVENT_HELPERS_HPP_INCLUDED LUA_EVENT_HELPERS_HPP_INCLUDED #include "LuaFunction.hpp" -#include "ssig.hpp" #include +#include #define LUA_EVENT_HELPERS_MAX_ARGS SSIG_MAX_ARGS @@ -26,12 +26,12 @@ else { } #define JD_EVENT_TABLE_BEGIN(ct) \ - ConnectionBase* ct##Meta::connectEvent( \ - lua_State* L, \ - Component* c, \ - std::string const& name) const \ - { \ - ct* cc = c->as(); \ + ssig::ConnectionBase* ct##Meta::connectEvent( \ + lua_State* L, \ + Component* c, \ + std::string const& name) const \ + { \ + ct* cc = c->as(); \ luabind::object recv(luabind::from_stack(L, -1)); \ using boost::ref; using boost::cref; @@ -39,9 +39,10 @@ template -ScopedConnection* makeConnection(Connection const& con) +ssig::ScopedConnection* makeConnection( + ssig::Connection const& con) { - return new ScopedConnection(con); + return new ssig::ScopedConnection(con); } #endif // include guard diff --git a/src/luaexport/TimerMeta.cpp b/src/luaexport/TimerMeta.cpp index d9e6aa4..b3253e4 100644 --- a/src/luaexport/TimerMeta.cpp +++ b/src/luaexport/TimerMeta.cpp @@ -39,7 +39,7 @@ static void init(LuaVm& vm) .LHPROPG(frameDuration) .property("factor", &LHCURCLASS::factor, &LHCURCLASS::setFactor) .scope [ - class_("CallOrder") + class_("CallOrder") ] # undef LHCURCLASS diff --git a/src/ssig.hpp b/src/ssig.hpp deleted file mode 100644 index 00877c9..0000000 --- a/src/ssig.hpp +++ /dev/null @@ -1,104 +0,0 @@ -// Part of the Jade Engine -- Copyright (c) Christian Neumüller 2012--2013 -// This file is subject to the terms of the BSD 2-Clause License. -// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause - -#ifndef SSIG_HPP_INCLUDED -#define SSIG_HPP_INCLUDED SSIG_HPP_INCLUDED - -#ifndef SSIG_MAX_ARGS -# define SSIG_MAX_ARGS 5 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class SsigError: public std::logic_error -{ -public: - SsigError(char const* msg): std::logic_error(msg) { } - SsigError(std::string const& msg): std::logic_error(msg) { } -}; - -namespace detail { - -template -inline R default_result() -{ - throw SsigError("attempt to invoke empty signal with non-void return type"); -} - -template<> -inline void default_result() -{ } - -template -inline bool check(bool isLast) { return isLast; } - -template <> -inline bool check(bool) { return false; } - -} // namespace detail - -class ConnectionBase -{ -public: - virtual ~ConnectionBase() {} - virtual void disconnect() = 0; - virtual bool isConnected() const = 0; -}; - - -template -class Signal; - -template -class Connection; - -template -class ScopedConnection; - -#define BOOST_PP_ITERATION_LIMITS (0, SSIG_MAX_ARGS) -#define BOOST_PP_FILENAME_1 "ssig_template.hpp" -#include BOOST_PP_ITERATE() - -#undef NARGS -#undef TYPES -#undef TRAILING_TMPL_PARAMS -#undef PRINT_TYPED_ARG -#undef PRINT_FORWARD_ARG -#undef TYPED_ARGS -#undef ARGS - -#define SSIG_DEFINE_MEMBERSIGNAL(name, signature) \ - public: \ - Signal::connection_type const connect_##name( \ - Signal::function_type const& slot) \ - { \ - return m_sig_##name.connect(slot); \ - } \ - private: Signal m_sig_##name; - - -#define SSIG_DEFINE_STATICSIGNAL(name, signature) \ - public: \ - static Signal::connection_type const connect_##name( \ - Signal::function_type const& slot) \ - { \ - return sig_##name().connect(slot); \ - } \ - private: \ - static Signal& sig_##name() \ - { \ - static Signal sig; \ - return sig; \ - } - -#endif diff --git a/src/ssig_template.hpp b/src/ssig_template.hpp deleted file mode 100644 index e1a1ad8..0000000 --- a/src/ssig_template.hpp +++ /dev/null @@ -1,233 +0,0 @@ -// Part of the Jade Engine -- Copyright (c) Christian Neumüller 2012--2013 -// This file is subject to the terms of the BSD 2-Clause License. -// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause - -#if !BOOST_PP_IS_ITERATING -# error "Do not include this file! Include ssig.hpp instead." -#endif - -#define NARGS BOOST_PP_ITERATION() - -#define TYPES BOOST_PP_ENUM_PARAMS(NARGS, A) -#define TRAILING_TMPL_PARAMS BOOST_PP_ENUM_TRAILING_PARAMS(NARGS, typename A) - -#define PRINT_TYPED_ARG(z, n, _) BOOST_PP_CAT(A, n) BOOST_PP_CAT(arg, n) -#define TYPED_ARGS BOOST_PP_ENUM(NARGS, PRINT_TYPED_ARG, BOOST_PP_EMPTY()) -#define PRINT_TYPED_ARG_RREF(z, n, _) BOOST_PP_CAT(A, n)&& BOOST_PP_CAT(arg, n) -#define TRAILING_TYPED_ARGS_RREF BOOST_PP_ENUM_TRAILING(NARGS, PRINT_TYPED_ARG_RREF, BOOST_PP_EMPTY()) -#define PRINT_FORWARD_ARG(z, n, _) std::forward(BOOST_PP_CAT(arg, n)) -#define ARGS BOOST_PP_ENUM(NARGS, PRINT_FORWARD_ARG, BOOST_PP_EMPTY()) - -template -void discard_result(F f TRAILING_TYPED_ARGS_RREF) -{ - f(ARGS); -} - -template -class Signal { -public: - typedef boost::function function_type; - typedef Connection connection_type; - - R const operator() (TYPED_ARGS) - { - for (auto it = m_slots.begin(); it != m_slots.end(); ) { - if (!it->slot) { - it = m_slots.erase(it); - } else { - if (detail::check(boost::next(it) == m_slots.end())) - return it->slot(ARGS); // return last result - it->slot(ARGS); // discard all other results - ++it; - } - } - return detail::default_result(); - } - - - connection_type connect(function_type const& slot); - - bool empty() const { return m_slots.empty(); } - - -private: - friend Connection; - - typedef std::list connection_container_type; - struct SlotRef: private boost::noncopyable { - SlotRef(function_type const& slot, connection_type* first_connection): - slot(slot) { connections.push_back(first_connection); } - SlotRef(SlotRef&& rhs): - connections(std::move(rhs.connections)), - slot(std::move(rhs.slot)) - { - } - ~SlotRef(); - connection_container_type connections; - function_type slot; - }; - - typedef std::list container_type; - container_type m_slots; - - -}; - -template -class Connection: public ConnectionBase { -public: - typedef Signal signal_type; - static_assert( - std::is_same::value, - "internal error: inconsistent typedef"); - - Connection(): m_signal(nullptr) { } // construct disconnected signal - - Connection(signal_type& signal, typename signal_type::function_type const& slot): - m_signal(&signal) - { - signal.m_slots.push_front(std::move( - typename Signal::SlotRef(slot, this))); - m_iterator = signal.m_slots.begin(); - } - - - ~Connection() - { - if (m_signal) - m_iterator->connections.remove(this); - } - - Connection(Connection const& rhs) - { - copyFrom(rhs); - } - - Connection(Connection&& rhs) - { - takeOver(std::move(rhs)); - } - - Connection& operator= (Connection const& rhs) - { - if (isConnected()) - disconnect(); - copyFrom(rhs); - return *this; - } - - Connection& operator= (Connection&& rhs) - { - if (isConnected()) - disconnect(); - takeOver(std::move(rhs)); - return *this; - } - - void disconnect() - { - checkSignal(); - m_iterator->slot.clear(); - m_iterator->connections.remove(this); - m_signal = nullptr; - } - - signal_type& signal() { checkSignal(); return *m_signal; } - - bool isConnected() const { return m_signal != nullptr; }; - - R invokeSlot(TYPED_ARGS) { return m_iterator->slot(ARGS); } - -private: - void takeOver(Connection&& rhs) - { - m_signal = rhs.m_signal; - rhs.m_signal = nullptr; - if (m_signal) { - m_iterator = rhs.m_iterator; - auto it = std::find( - m_iterator->connections.begin(), - m_iterator->connections.end(), &rhs); - assert(it != m_iterator->connections.end()); - *it = this; - } - } - - void copyFrom(Connection const& rhs) - { - m_signal = rhs.m_signal; - if (m_signal) { - m_iterator = rhs.m_iterator; - m_iterator->connections.push_back(this); - } - } - - friend Signal; - void signalDestroyed() { m_signal = nullptr; } - - void checkSignal() const - { - if (!m_signal) - throw SsigError("attempt to use a disconnected signal"); - } - - signal_type* m_signal; - typename signal_type::container_type::iterator m_iterator; -}; - -template -typename Signal::connection_type Signal::connect(function_type const& slot) -{ - return connection_type(*this, slot); -} - -template -Signal::SlotRef::~SlotRef() -{ - for (auto it = connections.begin(); it != connections.end(); ++it) { - (*it)->signalDestroyed(); - } -} - -template -class ScopedConnection: public Connection, private boost::noncopyable -{ - typedef Connection base_t; - typedef typename base_t::signal_type signal_type; -public: - ScopedConnection() { } - - ScopedConnection(signal_type& signal, typename signal_type::function_type const& slot): - base_t(signal, slot) - { } - - ScopedConnection(base_t const& rhs): - base_t(rhs) - { } - - ScopedConnection(ScopedConnection&& rhs): - base_t(std::move(rhs)) - { } - - ~ScopedConnection() - { - if (this->isConnected()) - this->disconnect(); - } - - ScopedConnection& operator= (base_t const& rhs) - { - base_t::operator=(rhs); - return *this; - } - - ScopedConnection& operator= (base_t&& rhs) - { - base_t::operator=(std::forward(rhs)); - return *this; - } - -private: - ScopedConnection& operator= (ScopedConnection const&); -}; diff --git a/src/svc/EventDispatcher.hpp b/src/svc/EventDispatcher.hpp index b83cd24..cb92208 100644 --- a/src/svc/EventDispatcher.hpp +++ b/src/svc/EventDispatcher.hpp @@ -6,9 +6,9 @@ #define EVENT_DISPATCHER_HPP_INCLUDED EVENT_DISPATCHER_HPP_INCLUDED #include "compsys/Component.hpp" -#include "ssig.hpp" #include +#include namespace sf { class Window; } diff --git a/src/svc/Mainloop.hpp b/src/svc/Mainloop.hpp index bd98e6a..b92c29b 100644 --- a/src/svc/Mainloop.hpp +++ b/src/svc/Mainloop.hpp @@ -8,7 +8,8 @@ namespace sf { class RenderWindow; } #include "compsys/Component.hpp" -#include "ssig.hpp" + +#include #include diff --git a/src/svc/Timer.hpp b/src/svc/Timer.hpp index ddf3467..41a6da4 100644 --- a/src/svc/Timer.hpp +++ b/src/svc/Timer.hpp @@ -6,11 +6,11 @@ #define TIMER_HPP_INCLUDED TIMER_HPP_INCLUDED #include "compsys/Component.hpp" -#include "ssig.hpp" #include #include #include +#include #include #include @@ -31,7 +31,7 @@ class Timer: public Component { }; public: - class CallOrder: public ConnectionBase { + class CallOrder: public ssig::ConnectionBase { public: virtual void disconnect() override; virtual bool isConnected() const override;