From 9c07e8c2e0e53f13980de572ef2270a547f3bef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Sun, 15 Mar 2015 19:57:14 +0000 Subject: [PATCH] Added Thread classes Added InputProfile in Controller Added ExecLuaCode --- doc/samples/Makefile.am | 7 +- doc/samples/meshviewer.cpp | 3 +- doc/samples/meshviewer.vcxproj | 1 + doc/tutorial/05_easymesh.cpp | 2 +- doc/tutorial/14_lol_lua.cpp | 2 +- src/Makefile.am | 1 + src/application/application.cpp | 2 +- src/input/controller.cpp | 107 +++++++++++++++++ src/input/controller.h | 207 +++++++++++++++++++++++++++++++- src/lol/sys/all.h | 1 + src/lol/sys/file.h | 1 + src/lol/sys/thread.h | 40 ++---- src/lol/sys/threadtypes.h | 98 +++++++++++++++ src/lolcore.vcxproj | 2 + src/lolcore.vcxproj.filters | 6 + src/lolua/baselua.cpp | 15 ++- src/lolua/baselua.h | 11 +- src/sys/file.cpp | 17 +++ src/sys/thread.cpp | 90 +++++++++++--- src/sys/threadbase.h | 62 ++++++++++ src/sys/threadtypes.cpp | 78 ++++++++++++ 21 files changed, 690 insertions(+), 63 deletions(-) create mode 100644 src/lol/sys/threadtypes.h create mode 100644 src/sys/threadtypes.cpp diff --git a/doc/samples/Makefile.am b/doc/samples/Makefile.am index 2c3aaab9..89f4ab78 100644 --- a/doc/samples/Makefile.am +++ b/doc/samples/Makefile.am @@ -41,12 +41,9 @@ nacl_phystest_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/bullet \ nacl_phystest_DEPENDENCIES = @LOL_DEPS@ nacl_phystest_LDFLAGS = $(AM_LDFLAGS) -meshviewer_SOURCES = meshviewer.cpp \ +meshviewer_SOURCES = meshviewer.cpp meshviewer.h \ shinymvtexture.lolfx shinyfur.lolfx \ - scenesetup.cpp scenesetup.h \ - scenesetup-compiler.cpp scenesetup-compiler.h \ - generated/scenesetup-scanner.cpp generated/scenesetup-scanner.h \ - generated/scenesetup-parser.cpp + scenesetup.cpp scenesetup.h meshviewer_CPPFLAGS = $(AM_CPPFLAGS) meshviewer_DEPENDENCIES = @LOL_DEPS@ meshviewer_LDFLAGS = $(AM_LDFLAGS) diff --git a/doc/samples/meshviewer.cpp b/doc/samples/meshviewer.cpp index da411517..1e7cabe8 100644 --- a/doc/samples/meshviewer.cpp +++ b/doc/samples/meshviewer.cpp @@ -18,6 +18,7 @@ #include #include "scenesetup.h" +#include "meshviewer.h" using namespace lol; @@ -184,7 +185,7 @@ public: m_controller = nullptr; //Scene setup - m_setup_loader.ExecLua("meshviewer_init.lua"); + m_setup_loader.ExecLuaFile("meshviewer_init.lua"); //Compile ref meshes m_gizmos << new EasyMesh(); diff --git a/doc/samples/meshviewer.vcxproj b/doc/samples/meshviewer.vcxproj index a454244c..f7b884f5 100644 --- a/doc/samples/meshviewer.vcxproj +++ b/doc/samples/meshviewer.vcxproj @@ -91,6 +91,7 @@ + diff --git a/doc/tutorial/05_easymesh.cpp b/doc/tutorial/05_easymesh.cpp index 5ee5fca5..ea79b841 100644 --- a/doc/tutorial/05_easymesh.cpp +++ b/doc/tutorial/05_easymesh.cpp @@ -28,7 +28,7 @@ public: EasyMeshTutorial() { EasyMeshLuaLoader EzMhLoader; - EzMhLoader.ExecLua("05_easymesh.lua"); + EzMhLoader.ExecLuaFile("05_easymesh.lua"); EasyMeshLuaObject* gears0 = EzMhLoader.GetPtr("g0"); EasyMeshLuaObject* gears1 = EzMhLoader.GetPtr("g1"); diff --git a/doc/tutorial/14_lol_lua.cpp b/doc/tutorial/14_lol_lua.cpp index 09d1e475..97d1805b 100644 --- a/doc/tutorial/14_lol_lua.cpp +++ b/doc/tutorial/14_lol_lua.cpp @@ -152,7 +152,7 @@ public: LoluaDemoLoader* demo_loader = new LoluaDemoLoader(); //Execute script - demo_loader->ExecLua("14_lol_lua.lua"); + demo_loader->ExecLuaFile("14_lol_lua.lua"); demo_loader->TestStuff(); //Grab global test values diff --git a/src/Makefile.am b/src/Makefile.am index 50dff021..b80ecc1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -109,6 +109,7 @@ liblolcore_sources = \ \ sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \ sys/thread.cpp sys/threadbase.h \ + sys/threadtypes.cpp \ \ image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \ image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ diff --git a/src/application/application.cpp b/src/application/application.cpp index b14bf6bb..0977e6e5 100644 --- a/src/application/application.cpp +++ b/src/application/application.cpp @@ -72,7 +72,7 @@ static void AppCallback() Application::Application(char const *name, ivec2 resolution, float framerate) { data = new ApplicationData(name, resolution, framerate); - g_world.ExecLua("lua/init.lua"); + g_world.ExecLuaFile("lua/init.lua"); } bool Application::MustTick() diff --git a/src/input/controller.cpp b/src/input/controller.cpp index 821b76eb..dc440874 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -225,6 +225,7 @@ float AxisBinding::RetrieveCurrentValue() array Controller::controllers; +//----------------------------------------------------------------------------- Controller::Controller(String const &name, int nb_keys, int nb_axis) { m_gamegroup = GAMEGROUP_BEFORE; @@ -241,8 +242,15 @@ Controller::Controller(String const &name, int nb_keys, int nb_axis) controllers.Push(this); } +Controller::Controller(String const &name, InputProfile const& profile) + : Controller(name, 0, 0) +{ + Init(profile); +} + Controller::~Controller() { + ClearProfile(); for (int i = 0; i < controllers.Count(); ++i) { if (controllers[i] == this) @@ -253,6 +261,7 @@ Controller::~Controller() } } +//----------------------------------------------------------------------------- Controller* Controller::Get(String const &name) { for (int i = 0; i < controllers.Count(); ++i) @@ -263,6 +272,102 @@ Controller* Controller::Get(String const &name) return nullptr; } +//Input profile system -------------------------------------------------------- +void Controller::UnbindProfile() +{ + if (m_profile.IsEmpty()) + return; + + m_mutex.lock(); + + //Keyboard + if (m_keyboard) + { + for (InputProfile::Keyboard& key : m_profile.m_keys) + GetKey(key.m_idx).UnbindKeyboard(key.m_name); + m_keyboard = nullptr; + } + + //Mouse + if (m_mouse) + { + for (InputProfile::MouseKey& key : m_profile.m_mouse_keys) + GetKey(key.m_idx).UnbindMouse(key.m_name); + for (InputProfile::MouseAxis& axis : m_profile.m_mouse_axis) + GetAxis(axis.m_idx).UnbindMouse(axis.m_name); + m_mouse = nullptr; + } + + //Joystick + for (InputProfile::JoystickKey& key : m_profile.m_joystick_keys) + { + if (m_joystick_idx.Find(key.m_joy) != INDEX_NONE) + GetKey(key.m_idx).UnbindJoystick(key.m_joy, key.m_name); + } + for (InputProfile::JoystickAxis& axis : m_profile.m_joystick_axis) + { + if (m_joystick_idx.Find(axis.m_joy) != INDEX_NONE) + GetAxis(axis.m_idx).UnbindJoystick(axis.m_joy, axis.m_name); + } + m_joystick.Empty(); + m_joystick_idx.Empty(); + + m_mutex.unlock(); +} +//Input profile system -------------------------------------------------------- +void Controller::BindProfile(InputProfile const& setup) +{ + ASSERT(!setup.IsEmpty()); + + m_mutex.lock(); + m_profile = setup; + + m_keys.Resize(m_profile.GetKeyCount()); + m_axis.Resize(m_profile.GetAxisCount()); + + //Keyboard + m_keyboard = InputDevice::GetKeyboard(); + if (m_keyboard) + { + for (InputProfile::Keyboard& key : m_profile.m_keys) + GetKey(key.m_idx).BindKeyboard(key.m_name); + } + + //Mouse + m_mouse = InputDevice::GetMouse(); + if (m_mouse) + { + for (InputProfile::MouseKey& key : m_profile.m_mouse_keys) + GetKey(key.m_idx).BindMouse(key.m_name); + for (InputProfile::MouseAxis& axis : m_profile.m_mouse_axis) + GetAxis(axis.m_idx).BindMouse(axis.m_name); + } + + //Joystick + for (uint64_t joy_idx : m_profile.m_joystick) + { + class InputDevice* joystick = InputDevice::GetJoystick(joy_idx); + if (joystick) + { + m_joystick << joystick; + m_joystick_idx << joy_idx; + } + } + for (InputProfile::JoystickKey& key : m_profile.m_joystick_keys) + { + if (m_joystick_idx.Find(key.m_joy) != INDEX_NONE) + GetKey(key.m_idx).BindJoystick(key.m_joy, key.m_name); + } + for (InputProfile::JoystickAxis& axis : m_profile.m_joystick_axis) + { + if (m_joystick_idx.Find(axis.m_joy) != INDEX_NONE) + GetAxis(axis.m_idx).BindJoystick(axis.m_joy, axis.m_name); + } + + m_mutex.unlock(); +} + +//----------------------------------------------------------------------------- void Controller::TickGame(float seconds) { Entity::TickGame(seconds); @@ -286,6 +391,7 @@ void Controller::TickGame(float seconds) m_deactivate_nextframe = false; } +//----------------------------------------------------------------------------- void Controller::Activate() { m_activate_nextframe = true; @@ -298,6 +404,7 @@ void Controller::Deactivate() m_activate_nextframe = false; } +//----------------------------------------------------------------------------- array Controller::DeactivateAll() { array result; diff --git a/src/input/controller.h b/src/input/controller.h index 9e1a1b9e..0685a023 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -133,11 +133,190 @@ protected: friend class Controller; }; +//------------------------------------------------------------------------- +class InputProfile +{ + friend class Controller; +private: + //--------------------------------------------------------------------- + class Key + { + friend class Controller; + friend class InputProfile; + public: + Key() { } + Key(int idx, String const& name) : m_idx(idx), m_name(name) { } + Key(const Key& other) : m_idx(other.m_idx), m_name(other.m_name) { } + ~Key() { } + bool operator==(const Key& other) { return m_name == other.m_name; } + private: + int m_idx = 0; + String m_name; + }; + //--------------------------------------------------------------------- + class Joystick + { + friend class Controller; + friend class InputProfile; + public: + Joystick() { } + Joystick(uint64_t joy, int idx, String const& name) : m_joy(joy), m_idx(idx), m_name(name) { } + Joystick(const Joystick& other) : m_joy(other.m_joy), m_idx(other.m_idx), m_name(other.m_name) { } + ~Joystick() { } + bool operator==(const Joystick& other) { return m_name == other.m_name; } + private: + uint64_t m_joy = 0; + int m_idx = 0; + String m_name; + }; +public: + //--------------------------------------------------------------------- + class Keyboard : public Key + { + friend class Controller; + friend class InputProfile; + public: + Keyboard() : Key() { } + Keyboard(int idx, String const& name) : Key(idx, name) { } + Keyboard(const Keyboard& other) : Key(other.m_idx, other.m_name) { } + }; + //--------------------------------------------------------------------- + class MouseKey : public Key + { + friend class Controller; + friend class InputProfile; + public: + MouseKey() : Key() { } + MouseKey(int idx, String const& name) : Key(idx, name) { } + MouseKey(const Keyboard& other) : Key(other.m_idx, other.m_name) { } + }; + //--------------------------------------------------------------------- + class MouseAxis : public Key + { + friend class Controller; + friend class InputProfile; + public: + MouseAxis() : Key() { } + MouseAxis(int idx, String const& name) : Key(idx, name) { } + MouseAxis(const Keyboard& other) : Key(other.m_idx, other.m_name) { } + }; + //--------------------------------------------------------------------- + class JoystickKey : public Joystick + { + friend class Controller; + friend class InputProfile; + public: + JoystickKey() : Joystick() { } + JoystickKey(uint64_t joy, int idx, String const& name) : Joystick(joy, idx, name) { } + JoystickKey(const JoystickKey& other) : Joystick(other.m_joy, other.m_idx, other.m_name) { } + }; + //--------------------------------------------------------------------- + class JoystickAxis : public Joystick + { + friend class Controller; + friend class InputProfile; + public: + JoystickAxis() : Joystick() { } + JoystickAxis(uint64_t joy, int idx, String const& name) : Joystick(joy, idx, name) { } + JoystickAxis(const JoystickAxis& other) : Joystick(other.m_joy, other.m_idx, other.m_name) { } + }; +public: + InputProfile() { } + InputProfile(const InputProfile& other) + { + m_keys = other.m_keys; + m_mouse_keys = other.m_mouse_keys; + m_mouse_axis = other.m_mouse_axis; + m_joystick = other.m_joystick; + m_joystick_keys = other.m_joystick_keys; + m_joystick_axis = other.m_joystick_axis; + } + virtual ~InputProfile() { } + + bool IsEmpty() const + { + return !(GetKeyCount() && GetAxisCount()); + } + int GetKeyCount() const + { + return (int)(m_keys.Count() + m_mouse_keys.Count() + m_joystick_keys.Count()); + } + int GetAxisCount() const + { + return (int)(m_mouse_axis.Count() + m_joystick_axis.Count()); + } + InputProfile& operator<<(InputProfile::Keyboard const& binding) + { + m_keys.PushUnique(binding); + return *this; + } + InputProfile& operator<<(array const& bindings) + { + m_keys += bindings; + return *this; + } + InputProfile& operator<<(InputProfile::MouseKey const& binding) + { + m_mouse_keys.PushUnique(binding); + return *this; + } + InputProfile& operator<<(array const& bindings) + { + m_mouse_keys += bindings; + return *this; + } + InputProfile& operator<<(InputProfile::MouseAxis const& binding) + { + m_mouse_axis.PushUnique(binding); + return *this; + } + InputProfile& operator<<(array const& bindings) + { + m_mouse_axis += bindings; + return *this; + } + InputProfile& operator<<(InputProfile::JoystickKey const& binding) + { + m_joystick.PushUnique(binding.m_joy); + m_joystick_keys.PushUnique(binding); + return *this; + } + InputProfile& operator<<(array const& bindings) + { + for (InputProfile::JoystickKey const& binding : bindings) + m_joystick.PushUnique(binding.m_joy); + m_joystick_keys += bindings; + return *this; + } + InputProfile& operator<<(InputProfile::JoystickAxis const& binding) + { + m_joystick.PushUnique(binding.m_joy); + m_joystick_axis.PushUnique(binding); + return *this; + } + InputProfile& operator<<(array const& bindings) + { + for (InputProfile::JoystickAxis const& binding : bindings) + m_joystick.PushUnique(binding.m_joy); + m_joystick_axis += bindings; + return *this; + } + +private: + array m_keys; + array m_mouse_keys; + array m_mouse_axis; + array m_joystick; + array m_joystick_keys; + array m_joystick_axis; +}; + //----------------------------------------------------------------------------- class Controller : public Entity { public: - Controller(String const &name, int nb_keys, int nb_axis); + Controller(String const &name, int nb_keys = 0, int nb_axis = 0); + Controller(String const &name, InputProfile const& setup); virtual ~Controller(); virtual void TickGame(float seconds); @@ -149,21 +328,45 @@ public: /** Deactivate every active controller on next frame and return an array of deactivated (previously active) controllers */ static array DeactivateAll(); + /** Input profile system */ + void Init(InputProfile const& profile) + { + UnbindProfile(); + BindProfile(profile); + } + void ClearProfile() + { + UnbindProfile(); + } + + /** GetKeys/Axis stuff */ KeyBinding& GetKey(int index) { return m_keys[index]; } AxisBinding& GetAxis(int index) { return m_axis[index]; } static Controller* Get(String const &name); protected: + /** Input profile system */ + void UnbindProfile(); + void BindProfile(InputProfile const& setup); + +private: array m_keys; array m_axis; -private: static array controllers; String m_name; bool m_activate_nextframe; bool m_deactivate_nextframe; bool m_active; + + //Input profile stuff + mutex m_mutex; + class InputProfile m_profile; + class InputDevice* m_keyboard = nullptr; + class InputDevice* m_mouse = nullptr; + array m_joystick; + array m_joystick_idx; }; } /* namespace lol */ diff --git a/src/lol/sys/all.h b/src/lol/sys/all.h index af488274..cf492a35 100644 --- a/src/lol/sys/all.h +++ b/src/lol/sys/all.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include #include #include diff --git a/src/lol/sys/file.h b/src/lol/sys/file.h index c5686e71..dd427a85 100644 --- a/src/lol/sys/file.h +++ b/src/lol/sys/file.h @@ -82,6 +82,7 @@ public: long int GetPosFromStart(); void SetPosFromStart(long int pos); long int GetSize(); + long int GetModificationTime(); private: class FileData *m_data; diff --git a/src/lol/sys/thread.h b/src/lol/sys/thread.h index 88d04431..e081ef62 100644 --- a/src/lol/sys/thread.h +++ b/src/lol/sys/thread.h @@ -38,7 +38,6 @@ public: queue() : queue_base() {} }; -#if LOL_FEATURE_THREADS class thread : thread_base { public: @@ -91,6 +90,7 @@ protected: }; typedef SafeEnum ThreadJobType; +//ThreadJob ------------------------------------------------------------------- class ThreadJob { friend class BaseThreadManager; @@ -109,11 +109,12 @@ protected: ThreadJobType m_type; }; -//Base class for thread manager +//Base class for thread manager ----------------------------------------------- class BaseThreadManager : public Entity { public: BaseThreadManager(int thread_count); + BaseThreadManager(int thread_count, int thread_min); ~BaseThreadManager(); char const *GetName() { return ""; } @@ -122,7 +123,16 @@ public: bool Start(); //Stop the threads bool Stop(); + + //Children class intergace + virtual bool AddJob(ThreadJob* job) { ASSERT(false); return false; } + virtual bool GetWorkResult(array& results) { ASSERT(false); return false; } + protected: + //Thread addition + void AddThreads(int nb); + void StopThreads(int nb); + //Work stuff bool AddWork(ThreadJob* job); @@ -137,6 +147,7 @@ protected: /* Worker threads */ int m_thread_count; + int m_thread_min; array m_threads; queue m_spawnqueue, m_donequeue; queue m_jobqueue; @@ -144,30 +155,5 @@ protected: array m_job_dispatch; }; -//Generic class for thread manager, executes work and store results, for you to use -class GenericThreadManager : public BaseThreadManager -{ -public: - GenericThreadManager(int thread_count) - : BaseThreadManager(thread_count) { } - - char const *GetName() { return ""; } - - //Work stuff - bool AddJob(ThreadJob* job) { return AddWork(job); } - bool GetWorkResult(array& results) - { - results += m_job_result; - m_job_result.Empty(); - return results.Count() > 0; - } - -protected: - virtual void TreatResult(ThreadJob* result) { m_job_result << result; } - - array m_job_result; -}; -#endif - } /* namespace lol */ diff --git a/src/lol/sys/threadtypes.h b/src/lol/sys/threadtypes.h new file mode 100644 index 00000000..34f4b885 --- /dev/null +++ b/src/lol/sys/threadtypes.h @@ -0,0 +1,98 @@ +// +// Lol Engine +// +// Copyright © 2010—2015 Sam Hocevar +// © 2013—2015 Benjamin "Touky" Huet +// +// This library is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#pragma once + +// +// The Threading classes +// --------------------- +// + +namespace lol +{ + +//Generic class for thread manager, executes work and store results, with no specific treatment +class DefaultThreadManager : public BaseThreadManager +{ +public: + DefaultThreadManager(int thread_count) + : DefaultThreadManager(thread_count, thread_count) + { } + DefaultThreadManager(int thread_count, int thread_min) + : DefaultThreadManager(thread_count, thread_min) + { } + + char const *GetName() { return ""; } + + //Work stuff + bool AddJob(ThreadJob* job); + bool GetWorkResult(array& results); + +protected: + virtual void TreatResult(ThreadJob* result) { m_job_result << result; } + array m_job_result; +}; + +//FileUpdateTesterJob --------------------------------------------------------- +class FileUpdateTesterJob : public ThreadJob +{ +public: + FileUpdateTesterJob() + : ThreadJob(ThreadJobType::NONE) { } + FileUpdateTesterJob(String path) + : ThreadJob(ThreadJobType::WORK_TODO) + { m_path = path; } + String& GetPath() { return m_path; } + bool HasUpdated() { return m_updated; } + void Restart() + { + SetJobType(ThreadJobType::WORK_TODO); + m_updated = false; + } + +protected: + virtual bool DoWork(); + + //----------------- + bool m_ready = false; + String m_path = String(); + long int m_time = 0; + bool m_updated = false; +}; + +//Test the files registered and warns when they update ------------------------ +class FileUpdateTester : public BaseThreadManager +{ + typedef BaseThreadManager super; +public: + struct Status + { + bool m_updated = false; + }; +public: + FileUpdateTester() : BaseThreadManager(1) { } + ~FileUpdateTester() { } + char const *GetName() { return ""; } + + //------------------------------------------------------------------------- + FileUpdateTester::Status* RegisterFile(String const& path); + virtual void TickGame(float seconds); + virtual void TreatResult(ThreadJob* result); + +private: + array m_job_done; + map m_files; +}; + +} /* namespace lol */ + diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 11eb2ae5..f3b0960f 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -222,6 +222,7 @@ + @@ -319,6 +320,7 @@ + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index 57917708..273d5f77 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -412,6 +412,9 @@ lolua + + sys + @@ -769,6 +772,9 @@ lolua + + lol\sys + diff --git a/src/lolua/baselua.cpp b/src/lolua/baselua.cpp index 48d33564..03453040 100644 --- a/src/lolua/baselua.cpp +++ b/src/lolua/baselua.cpp @@ -33,6 +33,11 @@ class LuaBaseData return 0; } + static int LuaDoCode(LuaState *l, String const& s) + { + return luaL_dostring(l, s.C()); + } + static int LuaDoFile(LuaState *l) { if (lua_isnoneornil(l, 1)) @@ -53,7 +58,7 @@ class LuaBaseData f.Close(); Log::Debug("loading Lua file %s\n", pathlist[i].C()); - status = luaL_dostring(l, s.C()); + status = LuaDoCode(l, s); break; } } @@ -94,13 +99,19 @@ Loader::~Loader() } //----------------------------------------------------------------------------- -bool Loader::ExecLua(String const &lua) +bool Loader::ExecLuaFile(String const &lua) { const char* c = lua_pushstring(m_lua_state, lua.C()); int status = LuaBaseData::LuaDoFile(m_lua_state); return status == 0; } +//----------------------------------------------------------------------------- +bool Loader::ExecLuaCode(String const &lua) +{ + return 0 == LuaBaseData::LuaDoCode(m_lua_state, lua); +} + //----------------------------------------------------------------------------- LuaState* Loader::GetLuaState() { diff --git a/src/lolua/baselua.h b/src/lolua/baselua.h index 8cdf176d..8b192231 100644 --- a/src/lolua/baselua.h +++ b/src/lolua/baselua.h @@ -54,9 +54,9 @@ struct ObjectLib } ClassVarStr; ObjectLib(String class_name, - array statics, - array methods, - array variables) + array const& statics, + array const& methods, + array const& variables) { m_class_name = class_name; m_static_name = class_name + "_lib"; @@ -74,7 +74,7 @@ struct ObjectLib || m_methods.Last().func != nullptr) m_methods.Push({ nullptr, nullptr }); - for (ClassVar& cv : variables) + for (ClassVar const& cv : variables) { if (cv.name && cv.get && cv.set) { @@ -934,7 +934,8 @@ public: Loader(); virtual ~Loader(); - bool ExecLua(String const &lua); + bool ExecLuaFile(String const &lua); + bool ExecLuaCode(String const &lua); template T GetVar(String const &name) diff --git a/src/sys/file.cpp b/src/sys/file.cpp index 9831dfe6..97535b93 100644 --- a/src/sys/file.cpp +++ b/src/sys/file.cpp @@ -192,7 +192,18 @@ class FileData #endif } + long int GetModificationTime() + { +#if __ANDROID__ + return 0; +#elif HAVE_STDIO_H + return m_stat.st_mtime; +#else + return 0; +#endif + } + //----------------------- #if __ANDROID__ AAsset *m_asset; #elif HAVE_STDIO_H @@ -314,6 +325,12 @@ long int File::GetSize() return m_data->GetSize(); } +//-- +long int File::GetModificationTime() +{ + return m_data->GetModificationTime(); +} + //--------------- class DirectoryData { diff --git a/src/sys/thread.cpp b/src/sys/thread.cpp index 8ed8ee60..a706b3a8 100644 --- a/src/sys/thread.cpp +++ b/src/sys/thread.cpp @@ -16,9 +16,16 @@ namespace lol { -#if LOL_FEATURE_THREADS +//BaseThreadManager ----------------------------------------------------------- BaseThreadManager::BaseThreadManager(int thread_count) { + m_thread_min = thread_count; + m_thread_count = thread_count; +} + +BaseThreadManager::BaseThreadManager(int thread_min, int thread_count) +{ + m_thread_min = thread_min; m_thread_count = thread_count; } @@ -30,16 +37,12 @@ BaseThreadManager::~BaseThreadManager() //Initialize, Ticker::Ref and start the thread bool BaseThreadManager::Start() { - if (m_threads.Count() > 0) + if (m_threads.count() > 0) return false; - /* Spawn worker threads and wait for their readiness. */ + //Add minimum threads m_threads.Resize(m_thread_count); - for (int i = 0; i < m_thread_count; i++) - m_threads[i] = new thread(std::bind(&BaseThreadManager::BaseThreadWork, - this)); - for (int i = 0; i < m_thread_count; i++) - m_spawnqueue.pop(); + AddThreads(m_thread_min); return true; } @@ -47,18 +50,44 @@ bool BaseThreadManager::Start() //Stop the threads bool BaseThreadManager::Stop() { - if (m_threads.Count() <= 0) + if (m_threads.count() <= 0) return false; - /* Signal worker threads for completion and wait for - * them to quit. */ - ThreadJob stop_job(ThreadJobType::THREAD_STOP); + //Stop all threads + StopThreads(m_threads.count()); + + return true; +} + +//---- +void BaseThreadManager::AddThreads(int nb) +{ + //Don't add threads if not availables +#if LOL_FEATURE_THREADS + //Spawn worker threads and ... + for (int i = 0; i < nb; i++) + m_threads << new thread(std::bind(&BaseThreadManager::BaseThreadWork, this)); + + //... Wait for their readiness. for (int i = 0; i < m_thread_count; i++) + m_spawnqueue.pop(); +#endif //LOL_FEATURE_THREADS +} + +//---- +void BaseThreadManager::StopThreads(int nb) +{ + //Don't stop threads if not availables +#if LOL_FEATURE_THREADS + //Signal worker threads for completion and ... + ThreadJob stop_job(ThreadJobType::THREAD_STOP); + for (int i = 0; i < nb; i++) m_jobqueue.push(&stop_job); - for (int i = 0; i < m_thread_count; i++) + + //... Wait for them to quit. + for (int i = 0; i < nb; i++) m_donequeue.pop(); - - return true; +#endif //LOL_FEATURE_THREADS } //Work stuff @@ -69,23 +98,34 @@ bool BaseThreadManager::AddWork(ThreadJob* job) return false; } +//---- bool BaseThreadManager::FetchResult(array& results) { ThreadJob* result; while (m_resultqueue.try_pop(result)) results << result; - return results.Count() > 0; + return results.count() > 0; } //Base thread work function void BaseThreadManager::BaseThreadWork() { +#if !LOL_FEATURE_THREADS + //Register that the thread has started m_spawnqueue.push(ThreadStatus::THREAD_STARTED); for ( ; ; ) +#endif //!LOL_FEATURE_THREADS { + //Try to retrieve a job ThreadJob* job = m_jobqueue.pop(); + //Stop thread if (job->GetJobType() == ThreadJobType::THREAD_STOP) + { +#if !LOL_FEATURE_THREADS break; +#endif //!LOL_FEATURE_THREADS + } + //Or work else if (*job == ThreadJobType::WORK_TODO) { if (job->DoWork()) @@ -95,9 +135,13 @@ void BaseThreadManager::BaseThreadWork() m_resultqueue.push(job); } } +#if !LOL_FEATURE_THREADS + //Register that the thread has stopped m_donequeue.push(ThreadStatus::THREAD_STOPPED); +#endif //!LOL_FEATURE_THREADS } +//---- void BaseThreadManager::TickGame(float seconds) { Entity::TickGame(seconds); @@ -109,11 +153,16 @@ void BaseThreadManager::TickGame(float seconds) while (m_job_dispatch.Count() > 0 && AddWork(m_job_dispatch.Last())) m_job_dispatch.pop(); + //Execute one task per frame if thread are not available +#if !LOL_FEATURE_THREADS + BaseThreadWork(); +#endif // !LOL_FEATURE_THREADS + array result; //Fetch and treat results if (FetchResult(result)) { - for (int i = 0; i < result.Count(); i++) + for (int i = 0; i < result.count(); i++) { ThreadJob* job = result[i]; if (job->GetJobType() == ThreadJobType::WORK_DONE) @@ -123,7 +172,12 @@ void BaseThreadManager::TickGame(float seconds) } } } + + //Resize thread count if needed + if (m_threads.count() > m_jobqueue.count() && m_threads.count() > m_thread_min) + StopThreads(m_threads.Count() - m_thread_min); + else if (m_threads.count() < m_jobqueue.count()) + AddThreads(lol::min(m_jobqueue.count(), (ptrdiff_t)m_thread_count) - m_threads.count()); } -#endif //LOL_FEATURE_THREADS } /* namespace lol */ diff --git a/src/sys/threadbase.h b/src/sys/threadbase.h index b4746bee..62006a1d 100644 --- a/src/sys/threadbase.h +++ b/src/sys/threadbase.h @@ -114,6 +114,68 @@ public: #endif } + ptrdiff_t count() + { + ptrdiff_t current_count = 0; +#if defined HAVE_PTHREAD_H + pthread_mutex_lock(&m_mutex); + /* If queue is full, wait on the "full" cond var. */ + m_pushers++; + while (m_count == CAPACITY) + pthread_cond_wait(&m_full_cond, &m_mutex); + m_pushers--; +#elif defined _WIN32 + WaitForSingleObject(m_empty_sem, INFINITE); + EnterCriticalSection(&m_mutex); +#endif + + current_count = (ptrdiff_t)m_count; + +#if defined HAVE_PTHREAD_H + /* If there were poppers waiting, signal the "empty" cond var. */ + if (m_poppers) + pthread_cond_signal(&m_empty_cond); + pthread_mutex_unlock(&m_mutex); +#elif defined _WIN32 + LeaveCriticalSection(&m_mutex); + ReleaseSemaphore(m_full_sem, 1, nullptr); +#endif + return current_count; + } + + ptrdiff_t try_count() + { + ptrdiff_t current_count = 0; + +#if defined HAVE_PTHREAD_H + pthread_mutex_lock(&m_mutex); + /* If queue is full, wait on the "full" cond var. */ + if (m_count == CAPACITY) + { + pthread_mutex_unlock(&m_mutex); + return false; + } +#elif defined _WIN32 + DWORD status = WaitForSingleObject(m_empty_sem, 0); + if (status == WAIT_TIMEOUT) + return 0; + EnterCriticalSection(&m_mutex); +#endif + + current_count = (ptrdiff_t)m_count; + +#if defined HAVE_PTHREAD_H + /* If there were poppers waiting, signal the "empty" cond var. */ + if (m_poppers) + pthread_cond_signal(&m_empty_cond); + pthread_mutex_unlock(&m_mutex); +#elif defined _WIN32 + LeaveCriticalSection(&m_mutex); + ReleaseSemaphore(m_full_sem, 1, nullptr); +#endif + return current_count; + } + void push(T value) { #if defined HAVE_PTHREAD_H diff --git a/src/sys/threadtypes.cpp b/src/sys/threadtypes.cpp new file mode 100644 index 00000000..f3f9675e --- /dev/null +++ b/src/sys/threadtypes.cpp @@ -0,0 +1,78 @@ +// +// Lol Engine +// +// Copyright © 2010—2015 Sam Hocevar +// © 2014—2015 Benjamin "Touky" Huet +// +// This library is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#include + +using namespace lol; + +//DefaultThreadManager -------------------------------------------------------- +bool DefaultThreadManager::AddJob(ThreadJob* job) +{ + return AddWork(job); +} +bool DefaultThreadManager::GetWorkResult(array& results) +{ + results += m_job_result; + m_job_result.Empty(); + return results.Count() > 0; +} + +//FileUpdateTesterJob --------------------------------------------------------- +bool FileUpdateTesterJob::DoWork() +{ + File f; + f.Open(m_path, FileAccess::Read); + if (!f.IsValid()) + return false; + if (!m_ready) + m_time = f.GetModificationTime(); + else + { + long int new_time = f.GetModificationTime(); + if (new_time > m_time) + m_updated = true; + } + return true; +} + +//FileUpdateTester ------------------------------------------------------------ +FileUpdateTester::Status* FileUpdateTester::RegisterFile(String const& path) +{ + m_job_dispatch << new FileUpdateTesterJob(path); + m_files[path] = new FileUpdateTester::Status(); + return m_files[path]; +} + +//------------------------------------------------------------------------- +void FileUpdateTester::TickGame(float seconds) +{ + super::TickGame(seconds); + + if (!m_job_dispatch.count() && m_job_done.count()) + { + m_job_dispatch = m_job_done; + m_job_done.empty(); + } +} + +//------------------------------------------------------------------------- +void FileUpdateTester::TreatResult(ThreadJob* result) +{ + FileUpdateTesterJob* job = static_cast(result); + if (job->HasUpdated()) + { + m_files[job->GetPath()]->m_updated = true; + job->Restart(); + m_job_done << job; + } +}