| @@ -41,12 +41,9 @@ nacl_phystest_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/bullet \ | |||||
| nacl_phystest_DEPENDENCIES = @LOL_DEPS@ | nacl_phystest_DEPENDENCIES = @LOL_DEPS@ | ||||
| nacl_phystest_LDFLAGS = $(AM_LDFLAGS) | nacl_phystest_LDFLAGS = $(AM_LDFLAGS) | ||||
| meshviewer_SOURCES = meshviewer.cpp \ | |||||
| meshviewer_SOURCES = meshviewer.cpp meshviewer.h \ | |||||
| shinymvtexture.lolfx shinyfur.lolfx \ | 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_CPPFLAGS = $(AM_CPPFLAGS) | ||||
| meshviewer_DEPENDENCIES = @LOL_DEPS@ | meshviewer_DEPENDENCIES = @LOL_DEPS@ | ||||
| meshviewer_LDFLAGS = $(AM_LDFLAGS) | meshviewer_LDFLAGS = $(AM_LDFLAGS) | ||||
| @@ -18,6 +18,7 @@ | |||||
| #include <lol/engine.h> | #include <lol/engine.h> | ||||
| #include "scenesetup.h" | #include "scenesetup.h" | ||||
| #include "meshviewer.h" | |||||
| using namespace lol; | using namespace lol; | ||||
| @@ -184,7 +185,7 @@ public: | |||||
| m_controller = nullptr; | m_controller = nullptr; | ||||
| //Scene setup | //Scene setup | ||||
| m_setup_loader.ExecLua("meshviewer_init.lua"); | |||||
| m_setup_loader.ExecLuaFile("meshviewer_init.lua"); | |||||
| //Compile ref meshes | //Compile ref meshes | ||||
| m_gizmos << new EasyMesh(); | m_gizmos << new EasyMesh(); | ||||
| @@ -91,6 +91,7 @@ | |||||
| <LolFxCompile Include="shinymvtexture.lolfx" /> | <LolFxCompile Include="shinymvtexture.lolfx" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <ClInclude Include="meshviewer.h" /> | |||||
| <ClInclude Include="scenesetup.h" /> | <ClInclude Include="scenesetup.h" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||
| <PropertyGroup Label="Globals"> | <PropertyGroup Label="Globals"> | ||||
| @@ -28,7 +28,7 @@ public: | |||||
| EasyMeshTutorial() | EasyMeshTutorial() | ||||
| { | { | ||||
| EasyMeshLuaLoader EzMhLoader; | EasyMeshLuaLoader EzMhLoader; | ||||
| EzMhLoader.ExecLua("05_easymesh.lua"); | |||||
| EzMhLoader.ExecLuaFile("05_easymesh.lua"); | |||||
| EasyMeshLuaObject* gears0 = EzMhLoader.GetPtr<EasyMeshLuaObject>("g0"); | EasyMeshLuaObject* gears0 = EzMhLoader.GetPtr<EasyMeshLuaObject>("g0"); | ||||
| EasyMeshLuaObject* gears1 = EzMhLoader.GetPtr<EasyMeshLuaObject>("g1"); | EasyMeshLuaObject* gears1 = EzMhLoader.GetPtr<EasyMeshLuaObject>("g1"); | ||||
| @@ -152,7 +152,7 @@ public: | |||||
| LoluaDemoLoader* demo_loader = new LoluaDemoLoader(); | LoluaDemoLoader* demo_loader = new LoluaDemoLoader(); | ||||
| //Execute script | //Execute script | ||||
| demo_loader->ExecLua("14_lol_lua.lua"); | |||||
| demo_loader->ExecLuaFile("14_lol_lua.lua"); | |||||
| demo_loader->TestStuff(); | demo_loader->TestStuff(); | ||||
| //Grab global test values | //Grab global test values | ||||
| @@ -109,6 +109,7 @@ liblolcore_sources = \ | |||||
| \ | \ | ||||
| sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \ | sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \ | ||||
| sys/thread.cpp sys/threadbase.h \ | sys/thread.cpp sys/threadbase.h \ | ||||
| sys/threadtypes.cpp \ | |||||
| \ | \ | ||||
| image/image.cpp image/image-private.h image/kernel.cpp image/pixel.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 \ | image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ | ||||
| @@ -72,7 +72,7 @@ static void AppCallback() | |||||
| Application::Application(char const *name, ivec2 resolution, float framerate) | Application::Application(char const *name, ivec2 resolution, float framerate) | ||||
| { | { | ||||
| data = new ApplicationData(name, resolution, framerate); | data = new ApplicationData(name, resolution, framerate); | ||||
| g_world.ExecLua("lua/init.lua"); | |||||
| g_world.ExecLuaFile("lua/init.lua"); | |||||
| } | } | ||||
| bool Application::MustTick() | bool Application::MustTick() | ||||
| @@ -225,6 +225,7 @@ float AxisBinding::RetrieveCurrentValue() | |||||
| array<Controller*> Controller::controllers; | array<Controller*> Controller::controllers; | ||||
| //----------------------------------------------------------------------------- | |||||
| Controller::Controller(String const &name, int nb_keys, int nb_axis) | Controller::Controller(String const &name, int nb_keys, int nb_axis) | ||||
| { | { | ||||
| m_gamegroup = GAMEGROUP_BEFORE; | m_gamegroup = GAMEGROUP_BEFORE; | ||||
| @@ -241,8 +242,15 @@ Controller::Controller(String const &name, int nb_keys, int nb_axis) | |||||
| controllers.Push(this); | controllers.Push(this); | ||||
| } | } | ||||
| Controller::Controller(String const &name, InputProfile const& profile) | |||||
| : Controller(name, 0, 0) | |||||
| { | |||||
| Init(profile); | |||||
| } | |||||
| Controller::~Controller() | Controller::~Controller() | ||||
| { | { | ||||
| ClearProfile(); | |||||
| for (int i = 0; i < controllers.Count(); ++i) | for (int i = 0; i < controllers.Count(); ++i) | ||||
| { | { | ||||
| if (controllers[i] == this) | if (controllers[i] == this) | ||||
| @@ -253,6 +261,7 @@ Controller::~Controller() | |||||
| } | } | ||||
| } | } | ||||
| //----------------------------------------------------------------------------- | |||||
| Controller* Controller::Get(String const &name) | Controller* Controller::Get(String const &name) | ||||
| { | { | ||||
| for (int i = 0; i < controllers.Count(); ++i) | for (int i = 0; i < controllers.Count(); ++i) | ||||
| @@ -263,6 +272,102 @@ Controller* Controller::Get(String const &name) | |||||
| return nullptr; | 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) | void Controller::TickGame(float seconds) | ||||
| { | { | ||||
| Entity::TickGame(seconds); | Entity::TickGame(seconds); | ||||
| @@ -286,6 +391,7 @@ void Controller::TickGame(float seconds) | |||||
| m_deactivate_nextframe = false; | m_deactivate_nextframe = false; | ||||
| } | } | ||||
| //----------------------------------------------------------------------------- | |||||
| void Controller::Activate() | void Controller::Activate() | ||||
| { | { | ||||
| m_activate_nextframe = true; | m_activate_nextframe = true; | ||||
| @@ -298,6 +404,7 @@ void Controller::Deactivate() | |||||
| m_activate_nextframe = false; | m_activate_nextframe = false; | ||||
| } | } | ||||
| //----------------------------------------------------------------------------- | |||||
| array<Controller*> Controller::DeactivateAll() | array<Controller*> Controller::DeactivateAll() | ||||
| { | { | ||||
| array<Controller*> result; | array<Controller*> result; | ||||
| @@ -133,11 +133,190 @@ protected: | |||||
| friend class Controller; | 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<InputProfile::Keyboard> const& bindings) | |||||
| { | |||||
| m_keys += bindings; | |||||
| return *this; | |||||
| } | |||||
| InputProfile& operator<<(InputProfile::MouseKey const& binding) | |||||
| { | |||||
| m_mouse_keys.PushUnique(binding); | |||||
| return *this; | |||||
| } | |||||
| InputProfile& operator<<(array<InputProfile::MouseKey> const& bindings) | |||||
| { | |||||
| m_mouse_keys += bindings; | |||||
| return *this; | |||||
| } | |||||
| InputProfile& operator<<(InputProfile::MouseAxis const& binding) | |||||
| { | |||||
| m_mouse_axis.PushUnique(binding); | |||||
| return *this; | |||||
| } | |||||
| InputProfile& operator<<(array<InputProfile::MouseAxis> 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<InputProfile::JoystickKey> 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<InputProfile::JoystickAxis> const& bindings) | |||||
| { | |||||
| for (InputProfile::JoystickAxis const& binding : bindings) | |||||
| m_joystick.PushUnique(binding.m_joy); | |||||
| m_joystick_axis += bindings; | |||||
| return *this; | |||||
| } | |||||
| private: | |||||
| array<Keyboard> m_keys; | |||||
| array<MouseKey> m_mouse_keys; | |||||
| array<MouseAxis> m_mouse_axis; | |||||
| array<uint64_t> m_joystick; | |||||
| array<JoystickKey> m_joystick_keys; | |||||
| array<JoystickAxis> m_joystick_axis; | |||||
| }; | |||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
| class Controller : public Entity | class Controller : public Entity | ||||
| { | { | ||||
| public: | 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 ~Controller(); | ||||
| virtual void TickGame(float seconds); | 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 */ | /** Deactivate every active controller on next frame and return an array of deactivated (previously active) controllers */ | ||||
| static array<Controller*> DeactivateAll(); | static array<Controller*> 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]; } | KeyBinding& GetKey(int index) { return m_keys[index]; } | ||||
| AxisBinding& GetAxis(int index) { return m_axis[index]; } | AxisBinding& GetAxis(int index) { return m_axis[index]; } | ||||
| static Controller* Get(String const &name); | static Controller* Get(String const &name); | ||||
| protected: | protected: | ||||
| /** Input profile system */ | |||||
| void UnbindProfile(); | |||||
| void BindProfile(InputProfile const& setup); | |||||
| private: | |||||
| array<KeyBinding> m_keys; | array<KeyBinding> m_keys; | ||||
| array<AxisBinding> m_axis; | array<AxisBinding> m_axis; | ||||
| private: | |||||
| static array<Controller*> controllers; | static array<Controller*> controllers; | ||||
| String m_name; | String m_name; | ||||
| bool m_activate_nextframe; | bool m_activate_nextframe; | ||||
| bool m_deactivate_nextframe; | bool m_deactivate_nextframe; | ||||
| bool m_active; | bool m_active; | ||||
| //Input profile stuff | |||||
| mutex m_mutex; | |||||
| class InputProfile m_profile; | |||||
| class InputDevice* m_keyboard = nullptr; | |||||
| class InputDevice* m_mouse = nullptr; | |||||
| array<class InputDevice*> m_joystick; | |||||
| array<uint64_t> m_joystick_idx; | |||||
| }; | }; | ||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| @@ -11,6 +11,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <lol/sys/thread.h> | #include <lol/sys/thread.h> | ||||
| #include <lol/sys/threadtypes.h> | |||||
| #include <lol/sys/init.h> | #include <lol/sys/init.h> | ||||
| #include <lol/sys/file.h> | #include <lol/sys/file.h> | ||||
| #include <lol/sys/timer.h> | #include <lol/sys/timer.h> | ||||
| @@ -82,6 +82,7 @@ public: | |||||
| long int GetPosFromStart(); | long int GetPosFromStart(); | ||||
| void SetPosFromStart(long int pos); | void SetPosFromStart(long int pos); | ||||
| long int GetSize(); | long int GetSize(); | ||||
| long int GetModificationTime(); | |||||
| private: | private: | ||||
| class FileData *m_data; | class FileData *m_data; | ||||
| @@ -38,7 +38,6 @@ public: | |||||
| queue() : queue_base<T, N>() {} | queue() : queue_base<T, N>() {} | ||||
| }; | }; | ||||
| #if LOL_FEATURE_THREADS | |||||
| class thread : thread_base | class thread : thread_base | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -91,6 +90,7 @@ protected: | |||||
| }; | }; | ||||
| typedef SafeEnum<ThreadJobTypeBase> ThreadJobType; | typedef SafeEnum<ThreadJobTypeBase> ThreadJobType; | ||||
| //ThreadJob ------------------------------------------------------------------- | |||||
| class ThreadJob | class ThreadJob | ||||
| { | { | ||||
| friend class BaseThreadManager; | friend class BaseThreadManager; | ||||
| @@ -109,11 +109,12 @@ protected: | |||||
| ThreadJobType m_type; | ThreadJobType m_type; | ||||
| }; | }; | ||||
| //Base class for thread manager | |||||
| //Base class for thread manager ----------------------------------------------- | |||||
| class BaseThreadManager : public Entity | class BaseThreadManager : public Entity | ||||
| { | { | ||||
| public: | public: | ||||
| BaseThreadManager(int thread_count); | BaseThreadManager(int thread_count); | ||||
| BaseThreadManager(int thread_count, int thread_min); | |||||
| ~BaseThreadManager(); | ~BaseThreadManager(); | ||||
| char const *GetName() { return "<BaseThreadManager>"; } | char const *GetName() { return "<BaseThreadManager>"; } | ||||
| @@ -122,7 +123,16 @@ public: | |||||
| bool Start(); | bool Start(); | ||||
| //Stop the threads | //Stop the threads | ||||
| bool Stop(); | bool Stop(); | ||||
| //Children class intergace | |||||
| virtual bool AddJob(ThreadJob* job) { ASSERT(false); return false; } | |||||
| virtual bool GetWorkResult(array<ThreadJob*>& results) { ASSERT(false); return false; } | |||||
| protected: | protected: | ||||
| //Thread addition | |||||
| void AddThreads(int nb); | |||||
| void StopThreads(int nb); | |||||
| //Work stuff | //Work stuff | ||||
| bool AddWork(ThreadJob* job); | bool AddWork(ThreadJob* job); | ||||
| @@ -137,6 +147,7 @@ protected: | |||||
| /* Worker threads */ | /* Worker threads */ | ||||
| int m_thread_count; | int m_thread_count; | ||||
| int m_thread_min; | |||||
| array<thread*> m_threads; | array<thread*> m_threads; | ||||
| queue<ThreadStatus> m_spawnqueue, m_donequeue; | queue<ThreadStatus> m_spawnqueue, m_donequeue; | ||||
| queue<ThreadJob*> m_jobqueue; | queue<ThreadJob*> m_jobqueue; | ||||
| @@ -144,30 +155,5 @@ protected: | |||||
| array<ThreadJob*> m_job_dispatch; | array<ThreadJob*> 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 "<GenericThreadManager>"; } | |||||
| //Work stuff | |||||
| bool AddJob(ThreadJob* job) { return AddWork(job); } | |||||
| bool GetWorkResult(array<ThreadJob*>& results) | |||||
| { | |||||
| results += m_job_result; | |||||
| m_job_result.Empty(); | |||||
| return results.Count() > 0; | |||||
| } | |||||
| protected: | |||||
| virtual void TreatResult(ThreadJob* result) { m_job_result << result; } | |||||
| array<ThreadJob*> m_job_result; | |||||
| }; | |||||
| #endif | |||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| @@ -0,0 +1,98 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net> | |||||
| // © 2013—2015 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||||
| // | |||||
| // 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 "<DefaultThreadManager>"; } | |||||
| //Work stuff | |||||
| bool AddJob(ThreadJob* job); | |||||
| bool GetWorkResult(array<ThreadJob*>& results); | |||||
| protected: | |||||
| virtual void TreatResult(ThreadJob* result) { m_job_result << result; } | |||||
| array<ThreadJob*> 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>"; } | |||||
| //------------------------------------------------------------------------- | |||||
| FileUpdateTester::Status* RegisterFile(String const& path); | |||||
| virtual void TickGame(float seconds); | |||||
| virtual void TreatResult(ThreadJob* result); | |||||
| private: | |||||
| array<ThreadJob*> m_job_done; | |||||
| map<String, Status*> m_files; | |||||
| }; | |||||
| } /* namespace lol */ | |||||
| @@ -222,6 +222,7 @@ | |||||
| <ClCompile Include="sys\hacks.cpp" /> | <ClCompile Include="sys\hacks.cpp" /> | ||||
| <ClCompile Include="sys\init.cpp" /> | <ClCompile Include="sys\init.cpp" /> | ||||
| <ClCompile Include="sys\thread.cpp" /> | <ClCompile Include="sys\thread.cpp" /> | ||||
| <ClCompile Include="sys\threadtypes.cpp" /> | |||||
| <ClCompile Include="sys\timer.cpp" /> | <ClCompile Include="sys\timer.cpp" /> | ||||
| <ClCompile Include="text.cpp" /> | <ClCompile Include="text.cpp" /> | ||||
| <ClCompile Include="ticker.cpp" /> | <ClCompile Include="ticker.cpp" /> | ||||
| @@ -319,6 +320,7 @@ | |||||
| <ClInclude Include="lol\sys\file.h" /> | <ClInclude Include="lol\sys\file.h" /> | ||||
| <ClInclude Include="lol\sys\init.h" /> | <ClInclude Include="lol\sys\init.h" /> | ||||
| <ClInclude Include="lol\sys\thread.h" /> | <ClInclude Include="lol\sys\thread.h" /> | ||||
| <ClInclude Include="lol\sys\threadtypes.h" /> | |||||
| <ClInclude Include="lol\sys\timer.h" /> | <ClInclude Include="lol\sys\timer.h" /> | ||||
| <ClInclude Include="lol\unit.h" /> | <ClInclude Include="lol\unit.h" /> | ||||
| <ClInclude Include="mesh\mesh.h" /> | <ClInclude Include="mesh\mesh.h" /> | ||||
| @@ -412,6 +412,9 @@ | |||||
| <ClCompile Include="lolua\baselua.cpp"> | <ClCompile Include="lolua\baselua.cpp"> | ||||
| <Filter>lolua</Filter> | <Filter>lolua</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="sys\threadtypes.cpp"> | |||||
| <Filter>sys</Filter> | |||||
| </ClCompile> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <ClInclude Include="debug\fps.h"> | <ClInclude Include="debug\fps.h"> | ||||
| @@ -769,6 +772,9 @@ | |||||
| <ClInclude Include="lolua\baselua.h"> | <ClInclude Include="lolua\baselua.h"> | ||||
| <Filter>lolua</Filter> | <Filter>lolua</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="lol\sys\threadtypes.h"> | |||||
| <Filter>lol\sys</Filter> | |||||
| </ClInclude> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <LolFxCompile Include="gpu\emptymaterial.lolfx"> | <LolFxCompile Include="gpu\emptymaterial.lolfx"> | ||||
| @@ -33,6 +33,11 @@ class LuaBaseData | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int LuaDoCode(LuaState *l, String const& s) | |||||
| { | |||||
| return luaL_dostring(l, s.C()); | |||||
| } | |||||
| static int LuaDoFile(LuaState *l) | static int LuaDoFile(LuaState *l) | ||||
| { | { | ||||
| if (lua_isnoneornil(l, 1)) | if (lua_isnoneornil(l, 1)) | ||||
| @@ -53,7 +58,7 @@ class LuaBaseData | |||||
| f.Close(); | f.Close(); | ||||
| Log::Debug("loading Lua file %s\n", pathlist[i].C()); | Log::Debug("loading Lua file %s\n", pathlist[i].C()); | ||||
| status = luaL_dostring(l, s.C()); | |||||
| status = LuaDoCode(l, s); | |||||
| break; | 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()); | const char* c = lua_pushstring(m_lua_state, lua.C()); | ||||
| int status = LuaBaseData::LuaDoFile(m_lua_state); | int status = LuaBaseData::LuaDoFile(m_lua_state); | ||||
| return status == 0; | return status == 0; | ||||
| } | } | ||||
| //----------------------------------------------------------------------------- | |||||
| bool Loader::ExecLuaCode(String const &lua) | |||||
| { | |||||
| return 0 == LuaBaseData::LuaDoCode(m_lua_state, lua); | |||||
| } | |||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
| LuaState* Loader::GetLuaState() | LuaState* Loader::GetLuaState() | ||||
| { | { | ||||
| @@ -54,9 +54,9 @@ struct ObjectLib | |||||
| } ClassVarStr; | } ClassVarStr; | ||||
| ObjectLib(String class_name, | ObjectLib(String class_name, | ||||
| array<ClassMethod> statics, | |||||
| array<ClassMethod> methods, | |||||
| array<ClassVar> variables) | |||||
| array<ClassMethod> const& statics, | |||||
| array<ClassMethod> const& methods, | |||||
| array<ClassVar> const& variables) | |||||
| { | { | ||||
| m_class_name = class_name; | m_class_name = class_name; | ||||
| m_static_name = class_name + "_lib"; | m_static_name = class_name + "_lib"; | ||||
| @@ -74,7 +74,7 @@ struct ObjectLib | |||||
| || m_methods.Last().func != nullptr) | || m_methods.Last().func != nullptr) | ||||
| m_methods.Push({ nullptr, nullptr }); | m_methods.Push({ nullptr, nullptr }); | ||||
| for (ClassVar& cv : variables) | |||||
| for (ClassVar const& cv : variables) | |||||
| { | { | ||||
| if (cv.name && cv.get && cv.set) | if (cv.name && cv.get && cv.set) | ||||
| { | { | ||||
| @@ -934,7 +934,8 @@ public: | |||||
| Loader(); | Loader(); | ||||
| virtual ~Loader(); | virtual ~Loader(); | ||||
| bool ExecLua(String const &lua); | |||||
| bool ExecLuaFile(String const &lua); | |||||
| bool ExecLuaCode(String const &lua); | |||||
| template<typename T> | template<typename T> | ||||
| T GetVar(String const &name) | T GetVar(String const &name) | ||||
| @@ -192,7 +192,18 @@ class FileData | |||||
| #endif | #endif | ||||
| } | } | ||||
| long int GetModificationTime() | |||||
| { | |||||
| #if __ANDROID__ | |||||
| return 0; | |||||
| #elif HAVE_STDIO_H | |||||
| return m_stat.st_mtime; | |||||
| #else | |||||
| return 0; | |||||
| #endif | |||||
| } | |||||
| //----------------------- | |||||
| #if __ANDROID__ | #if __ANDROID__ | ||||
| AAsset *m_asset; | AAsset *m_asset; | ||||
| #elif HAVE_STDIO_H | #elif HAVE_STDIO_H | ||||
| @@ -314,6 +325,12 @@ long int File::GetSize() | |||||
| return m_data->GetSize(); | return m_data->GetSize(); | ||||
| } | } | ||||
| //-- | |||||
| long int File::GetModificationTime() | |||||
| { | |||||
| return m_data->GetModificationTime(); | |||||
| } | |||||
| //--------------- | //--------------- | ||||
| class DirectoryData | class DirectoryData | ||||
| { | { | ||||
| @@ -16,9 +16,16 @@ | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| //BaseThreadManager ----------------------------------------------------------- | |||||
| BaseThreadManager::BaseThreadManager(int thread_count) | 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; | m_thread_count = thread_count; | ||||
| } | } | ||||
| @@ -30,16 +37,12 @@ BaseThreadManager::~BaseThreadManager() | |||||
| //Initialize, Ticker::Ref and start the thread | //Initialize, Ticker::Ref and start the thread | ||||
| bool BaseThreadManager::Start() | bool BaseThreadManager::Start() | ||||
| { | { | ||||
| if (m_threads.Count() > 0) | |||||
| if (m_threads.count() > 0) | |||||
| return false; | return false; | ||||
| /* Spawn worker threads and wait for their readiness. */ | |||||
| //Add minimum threads | |||||
| m_threads.Resize(m_thread_count); | 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; | return true; | ||||
| } | } | ||||
| @@ -47,18 +50,44 @@ bool BaseThreadManager::Start() | |||||
| //Stop the threads | //Stop the threads | ||||
| bool BaseThreadManager::Stop() | bool BaseThreadManager::Stop() | ||||
| { | { | ||||
| if (m_threads.Count() <= 0) | |||||
| if (m_threads.count() <= 0) | |||||
| return false; | 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++) | 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); | 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(); | m_donequeue.pop(); | ||||
| return true; | |||||
| #endif //LOL_FEATURE_THREADS | |||||
| } | } | ||||
| //Work stuff | //Work stuff | ||||
| @@ -69,23 +98,34 @@ bool BaseThreadManager::AddWork(ThreadJob* job) | |||||
| return false; | return false; | ||||
| } | } | ||||
| //---- | |||||
| bool BaseThreadManager::FetchResult(array<ThreadJob*>& results) | bool BaseThreadManager::FetchResult(array<ThreadJob*>& results) | ||||
| { | { | ||||
| ThreadJob* result; | ThreadJob* result; | ||||
| while (m_resultqueue.try_pop(result)) | while (m_resultqueue.try_pop(result)) | ||||
| results << result; | results << result; | ||||
| return results.Count() > 0; | |||||
| return results.count() > 0; | |||||
| } | } | ||||
| //Base thread work function | //Base thread work function | ||||
| void BaseThreadManager::BaseThreadWork() | void BaseThreadManager::BaseThreadWork() | ||||
| { | { | ||||
| #if !LOL_FEATURE_THREADS | |||||
| //Register that the thread has started | |||||
| m_spawnqueue.push(ThreadStatus::THREAD_STARTED); | m_spawnqueue.push(ThreadStatus::THREAD_STARTED); | ||||
| for ( ; ; ) | for ( ; ; ) | ||||
| #endif //!LOL_FEATURE_THREADS | |||||
| { | { | ||||
| //Try to retrieve a job | |||||
| ThreadJob* job = m_jobqueue.pop(); | ThreadJob* job = m_jobqueue.pop(); | ||||
| //Stop thread | |||||
| if (job->GetJobType() == ThreadJobType::THREAD_STOP) | if (job->GetJobType() == ThreadJobType::THREAD_STOP) | ||||
| { | |||||
| #if !LOL_FEATURE_THREADS | |||||
| break; | break; | ||||
| #endif //!LOL_FEATURE_THREADS | |||||
| } | |||||
| //Or work | |||||
| else if (*job == ThreadJobType::WORK_TODO) | else if (*job == ThreadJobType::WORK_TODO) | ||||
| { | { | ||||
| if (job->DoWork()) | if (job->DoWork()) | ||||
| @@ -95,9 +135,13 @@ void BaseThreadManager::BaseThreadWork() | |||||
| m_resultqueue.push(job); | m_resultqueue.push(job); | ||||
| } | } | ||||
| } | } | ||||
| #if !LOL_FEATURE_THREADS | |||||
| //Register that the thread has stopped | |||||
| m_donequeue.push(ThreadStatus::THREAD_STOPPED); | m_donequeue.push(ThreadStatus::THREAD_STOPPED); | ||||
| #endif //!LOL_FEATURE_THREADS | |||||
| } | } | ||||
| //---- | |||||
| void BaseThreadManager::TickGame(float seconds) | void BaseThreadManager::TickGame(float seconds) | ||||
| { | { | ||||
| Entity::TickGame(seconds); | Entity::TickGame(seconds); | ||||
| @@ -109,11 +153,16 @@ void BaseThreadManager::TickGame(float seconds) | |||||
| while (m_job_dispatch.Count() > 0 && AddWork(m_job_dispatch.Last())) | while (m_job_dispatch.Count() > 0 && AddWork(m_job_dispatch.Last())) | ||||
| m_job_dispatch.pop(); | m_job_dispatch.pop(); | ||||
| //Execute one task per frame if thread are not available | |||||
| #if !LOL_FEATURE_THREADS | |||||
| BaseThreadWork(); | |||||
| #endif // !LOL_FEATURE_THREADS | |||||
| array<ThreadJob*> result; | array<ThreadJob*> result; | ||||
| //Fetch and treat results | //Fetch and treat results | ||||
| if (FetchResult(result)) | if (FetchResult(result)) | ||||
| { | { | ||||
| for (int i = 0; i < result.Count(); i++) | |||||
| for (int i = 0; i < result.count(); i++) | |||||
| { | { | ||||
| ThreadJob* job = result[i]; | ThreadJob* job = result[i]; | ||||
| if (job->GetJobType() == ThreadJobType::WORK_DONE) | 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 */ | } /* namespace lol */ | ||||
| @@ -114,6 +114,68 @@ public: | |||||
| #endif | #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) | void push(T value) | ||||
| { | { | ||||
| #if defined HAVE_PTHREAD_H | #if defined HAVE_PTHREAD_H | ||||
| @@ -0,0 +1,78 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net> | |||||
| // © 2014—2015 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||||
| // | |||||
| // 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 <lol/engine-internal.h> | |||||
| using namespace lol; | |||||
| //DefaultThreadManager -------------------------------------------------------- | |||||
| bool DefaultThreadManager::AddJob(ThreadJob* job) | |||||
| { | |||||
| return AddWork(job); | |||||
| } | |||||
| bool DefaultThreadManager::GetWorkResult(array<ThreadJob*>& 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<FileUpdateTesterJob*>(result); | |||||
| if (job->HasUpdated()) | |||||
| { | |||||
| m_files[job->GetPath()]->m_updated = true; | |||||
| job->Restart(); | |||||
| m_job_done << job; | |||||
| } | |||||
| } | |||||