@@ -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; | |||||
} | |||||
} |