Browse Source

ImGui 1.37

MeshViewer first pass
undefined
Benjamin ‘Touky’ Huet Sam Hocevar <sam@hocevar.net> 10 years ago
parent
commit
3f167f2f1d
22 changed files with 650 additions and 304 deletions
  1. +1
    -1
      build/lol-build
  2. +1
    -1
      build/msbuild/lol.vars.props
  3. +1
    -1
      configure.ac
  4. +0
    -0
      doc/samples/data/meshviewer.easymesh.lua
  5. +2
    -2
      doc/samples/meshviewer.vcxproj
  6. +239
    -113
      doc/samples/meshviewer/meshviewer.cpp
  7. +16
    -2
      doc/samples/meshviewer/scenesetup.cpp
  8. +4
    -1
      doc/samples/meshviewer/scenesetup.h
  9. +3
    -3
      doc/tutorial/14_lol_lua.cpp
  10. +16
    -2
      src/easymesh/easymeshlua.cpp
  11. +12
    -9
      src/easymesh/easymeshlua.h
  12. +51
    -10
      src/input/controller.h
  13. +1
    -1
      src/input/input.cpp
  14. +1
    -1
      src/input/input.h
  15. +10
    -9
      src/lol/sys/thread.h
  16. +49
    -100
      src/lol/sys/threadtypes.h
  17. +4
    -2
      src/lolimgui.cpp
  18. +1
    -2
      src/lolimgui.h
  19. +40
    -0
      src/lolua/baselua.cpp
  20. +41
    -24
      src/lolua/baselua.h
  21. +1
    -3
      src/sys/thread.cpp
  22. +156
    -17
      src/sys/threadtypes.cpp

+ 1
- 1
build/lol-build View File

@@ -263,7 +263,7 @@ configure()
CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/gdk-pixbuf-2.0"
CPPFLAGS="$CPPFLAGS -I$PWD/external/gtk-2.22.1/include/atk-1.0"
CPPFLAGS="$CPPFLAGS -I$PWD/external/gtkglarea-2.0.1/include"
CPPFLAGS="$CPPFLAGS -I$PWD/external/imgui-1.36/include"
CPPFLAGS="$CPPFLAGS -I$PWD/external/imgui-1.37/include"
CPPFLAGS="$CPPFLAGS -mms-bitfields"
LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
GTK_LIBS="$GTK_LIBS -lgtkgl-2.0 -lopengl32 -lglew32 -lgdi32"


+ 1
- 1
build/msbuild/lol.vars.props View File

@@ -9,7 +9,7 @@
<PegtlIncludes>$(PegtlDir)\include</PegtlIncludes>

<!-- imgui -->
<ImguiDir>$(ExternalDir)\imgui-1.36</ImguiDir>
<ImguiDir>$(ExternalDir)\imgui-1.37</ImguiDir>
<ImguiIncludes>$(ImguiDir)</ImguiIncludes>

<!-- libgcc (from mingw-w64) -->


+ 1
- 1
configure.ac View File

@@ -295,7 +295,7 @@ fi

dnl Use Imgui? Yes, always
if true; then
LOL_CFLAGS="$LOL_CFLAGS -I\$(top_srcdir)/external/imgui-1.36"
LOL_CFLAGS="$LOL_CFLAGS -I\$(top_srcdir)/external/imgui-1.37"
fi




doc/samples/data/meshviewer_init.lua → doc/samples/data/meshviewer.easymesh.lua View File


+ 2
- 2
doc/samples/meshviewer.vcxproj View File

@@ -54,10 +54,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</None>
<None Include="data/meshviewer_buffer.lua">
<None Include="data/meshviewer_init.lua">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</None>
<None Include="data/meshviewer_init.lua">
<None Include="data\meshviewer.easymesh.lua">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</None>
<None Include="meshviewer/meshviewer.index.html">


+ 239
- 113
doc/samples/meshviewer/meshviewer.cpp View File

@@ -23,18 +23,19 @@ using namespace lol;

static int const TEXTURE_WIDTH = 256;

#define NO_NACL_EM (!__native_client__ && !EMSCRIPTEN)
#define NACL_EM (__native_client__ || EMSCRIPTEN)
#define NO_NACL_EM_INPUT (1)
//Basic build defines ---------------------------------------------------------
#define HAS_WEB (__native_client__ || EMSCRIPTEN)
#define HAS_INPUT (_WIN32 && !HAS_WEB)

//Basic config defines --------------------------------------------------------
#define R_M 1.f
#if NACL_EM
#if HAS_WEB
#define DEFAULT_WIDTH (800.f * R_M)
#define DEFAULT_HEIGHT (400.f * R_M)
#else
#define DEFAULT_WIDTH (1200.f * R_M)
#define DEFAULT_HEIGHT (400.f * R_M)
#endif //NACL_EM
#endif //HAS_WEB
#define WIDTH ((float)Video::GetSize().x)
#define HEIGHT ((float)Video::GetSize().y)
#define SCREEN_W (10.f / WIDTH)
@@ -65,27 +66,7 @@ static int const TEXTURE_WIDTH = 256;
LOLFX_RESOURCE_DECLARE(shinyfur);
LOLFX_RESOURCE_DECLARE(shinymvtexture);

enum GizmoType
{
GZ_Editor = 0,
GZ_LightPos,
GZ_LightDir,

GZ_MAX
};

struct LightData
{
LightData(vec3 pos, vec4 col)
{
m_pos = pos;
m_col = col;
}

vec3 m_pos;
vec4 m_col;
};

//TargetCamera ----------------------------------------------------------------
class TargetCamera
{
public:
@@ -114,21 +95,203 @@ public:
array<vec3> m_targets;
};

MeshViewer::MeshViewer(char const *file_name = "data/mesh-buffer.txt")
//EasyMeshLoadJob -------------------------------------------------------------
bool EasyMeshLoadJob::DoWork()
{
if (m_loader.ExecLuaFile(m_path))
{
array<EasyMeshLuaObject*>& objs = m_loader.GetInstances();
for (EasyMeshLuaObject* obj : objs)
m_meshes << new EasyMeshViewerObject(obj->GetMesh());
}
return !!m_meshes.count();
}

//-----------------------------------------------------------------------------
MeshViewerLoadJob* EasyMeshLoadJob::GetInstance(String const& path)
{
if (Check(path))
return new MeshViewerLoadJob(path);
return nullptr;
}

//-----------------------------------------------------------------------------
void EasyMeshLoadJob::RetrieveResult(class MeshViewer* app)
{
for (EasyMeshViewerObject* mesh : m_meshes)
app->AddViewerObj(mesh);
m_meshes.Empty();
}

//MeshViewer ------------------------------------------------------------------
MeshViewer::MeshViewer(char const *file_name)
: m_file_name(file_name)
{ }

//-----------------------------------------------------------------------------
MeshViewer::~MeshViewer()
{
m_init = false;
m_first_tick = false;
Stop();
}

// Message Service
MessageService::Setup();
//-----------------------------------------------------------------------------
void MeshViewer::Start()
{
/** OLD STUFF **/
//Prepare();

//Scene setup
m_setup_loader.ExecLuaFile("meshviewer_init.lua");

//Threads setup
m_entities << (m_file_check = new FileUpdateTester());
m_file_status = m_file_check->RegisterFile(m_file_name);

m_entities << (m_file_loader = new DefaultThreadManager(1, 1));

//Camera setup
m_camera = new Camera();
m_camera->SetView(vec3(0.f, 0.f, 10.f), vec3::zero, vec3::axis_y);
m_camera->SetProjection(0.f, .0001f, 2000.f, WIDTH * SCREEN_W, RATIO_HW);
m_camera->UseShift(true);
g_scene->PushCamera(m_camera);

#if HAS_INPUT
InputProfile& ip = m_profile;
ip.AddBindings<MeshViewerKeyInput, MeshViewerKeyInput::KBD_BEG, MeshViewerKeyInput::KBD_END>(InputProfileType::Keyboard);
ip.AddBindings<MeshViewerKeyInput, MeshViewerKeyInput::MSE_BEG, MeshViewerKeyInput::MSE_END>(InputProfileType::Keyboard);

m_entities << (m_controller = new Controller("MeshViewer"));
m_controller->Init(m_profile);
#endif //HAS_INPUT

/** ----- Register all entities ----- **/
for (Entity* entity : m_entities) Ticker::Ref(entity);

/** ----- Init is done ----- **/
m_init = true;

/** ----- Start threads ----- **/
m_file_check->Start();

}

//-----------------------------------------------------------------------------
void MeshViewer::Stop()
{
//Destroy core stuff
if (m_camera) g_scene->PopCamera(m_camera);
if (m_ssetup) delete m_ssetup;

m_file_check->UnregisterFile(m_file_status);

//Register all entities
for (Entity* entity : m_entities) Ticker::Unref(entity);
//Delete objs
while (m_objs.count()) delete m_objs.Pop();

//Nullify all
m_ssetup = nullptr;
m_camera = nullptr;
m_controller = nullptr;
m_file_check = nullptr;
m_file_loader = nullptr;

//Scene setup
m_setup_loader.ExecLuaFile("meshviewer_init.lua");
/** ----- Init is needed ----- **/
m_init = false;
}

//-----------------------------------------------------------------------------
MeshViewerLoadJob* MeshViewer::GetLoadJob(String const& path)
{
MeshViewerLoadJob* job = nullptr;
if (job = EasyMeshLoadJob::GetInstance(path)) return job;
return job;
}

//-----------------------------------------------------------------------------
void MeshViewer::TickGame(float seconds)
{
super::TickGame(seconds);

if (!m_init && g_scene) Start();
if (!m_init) return;

m_first_tick = true;

//Check file update
ASSERT(m_file_status);
if (m_file_status->HasUpdated())
{
MeshViewerLoadJob* job = GetLoadJob(m_file_name);
if (!job)
m_file_loader->AddWork(job);
}

//Check work done
{
array<ThreadJob*> result;
m_file_loader->GetWorkResult(result);
if (result.count())
{
for (ThreadJob* job : result)
{
if (job->GetJobType() == ThreadJobType::WORK_SUCCESSED)
{
MeshViewerLoadJob* mvjob = static_cast<MeshViewerLoadJob*>(job);
mvjob->RetrieveResult(this);
}
delete job;
}
}
}

/** OLD STUFF **/
//Update(seconds);
}

//-----------------------------------------------------------------------------
void MeshViewer::TickDraw(float seconds, Scene &scene)
{
super::TickDraw(seconds, scene);

/** OLD STUFF **/
//Draw(seconds);
}

//The basic main --------------------------------------------------------------
int main(int argc, char **argv)
{
System::Init(argc, argv);

Application app("MeshViewer", ivec2((int)DEFAULT_WIDTH, (int)DEFAULT_HEIGHT), 60.0f);
if (argc > 1)
new MeshViewer(argv[1]);
else
new MeshViewer();
app.Run();

return EXIT_SUCCESS;
}

//-------------------------------------------------------------------------
//OLD ---------------------------------------------------------------------
//-------------------------------------------------------------------------
#if HAS_INPUT
bool MeshViewer::KeyReleased(MVKeyboardList index) { return (HAS_KBOARD && m_controller->WasKeyReleasedThisFrame(index)); }
bool MeshViewer::KeyPressed(MVKeyboardList index) { return (HAS_KBOARD && m_controller->WasKeyPressedThisFrame(index)); }
bool MeshViewer::KeyDown(MVKeyboardList index) { return (HAS_KBOARD && m_controller->IsKeyPressed(index)); }
bool MeshViewer::KeyReleased(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->WasKeyReleasedThisFrame(index)); }
bool MeshViewer::KeyPressed(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->WasKeyPressedThisFrame(index)); }
bool MeshViewer::KeyDown(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->IsKeyPressed(index)); }
float MeshViewer::AxisValue(MVMouseAxisList index) { return (HAS_MOUSE) ? (m_controller->GetAxisValue(index)) : (0.f); }
#endif //HAS_INPUT

void MeshViewer::Prepare()
{
// Message Service
MessageService::Setup();

//Compile ref meshes
m_gizmos << new EasyMesh();
@@ -175,44 +338,18 @@ MeshViewer::MeshViewer(char const *file_name = "data/mesh-buffer.txt")
//stream update
m_stream_update_time = 2.0f;
m_stream_update_timer = 1.0f;
}

MeshViewer::~MeshViewer()
{
if (m_camera)
g_scene->PopCamera(m_camera);
if (m_ssetup)
delete m_ssetup;
MessageService::Destroy();

m_controller = nullptr;
m_camera = nullptr;
m_ssetup = nullptr;
}

#if NO_NACL_EM_INPUT
bool MeshViewer::KeyReleased(MVKeyboardList index) { return (HAS_KBOARD && m_controller->WasKeyReleasedThisFrame(index)); }
bool MeshViewer::KeyPressed(MVKeyboardList index) { return (HAS_KBOARD && m_controller->WasKeyPressedThisFrame(index)); }
bool MeshViewer::KeyDown(MVKeyboardList index) { return (HAS_KBOARD && m_controller->IsKeyPressed(index)); }
bool MeshViewer::KeyReleased(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->WasKeyReleasedThisFrame(index)); }
bool MeshViewer::KeyPressed(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->WasKeyPressedThisFrame(index)); }
bool MeshViewer::KeyDown(MVMouseKeyList index) { return (HAS_MOUSE && m_controller->IsKeyPressed(index)); }
float MeshViewer::AxisValue(MVMouseAxisList index) { return (HAS_MOUSE) ? (m_controller->GetAxisValue(index)) : (0.f); }
#endif //NO_NACL_EM_INPUT

void MeshViewer::Init()
{
m_init = true;
m_input_usage = 0;

#if NO_NACL_EM_INPUT
#if HAS_INPUT
/* Register an input controller for the keyboard */
m_controller = new Controller("Default");
m_controller->SetInputCount(MAX_KEYS, MAX_AXIS);

if (InputDevice::Get(g_name_mouse.C()))
{
m_input_usage |= (1<<IPT_MV_MOUSE);
m_input_usage |= (1 << IPT_MV_MOUSE);

m_controller->GetKey(MSE_CAM_ROT).BindMouse("Left");
m_controller->GetKey(MSE_CAM_POS).BindMouse("Right");
@@ -224,17 +361,17 @@ void MeshViewer::Init()

if (InputDevice::Get(g_name_keyboard.C()))
{
m_input_usage |= (1<<IPT_MV_KBOARD);
m_input_usage |= (1 << IPT_MV_KBOARD);

//Camera keyboard rotation
m_controller->GetKey(KEY_CAM_UP ).BindKeyboard("Up");
m_controller->GetKey(KEY_CAM_DOWN ).BindKeyboard("Down");
m_controller->GetKey(KEY_CAM_LEFT ).BindKeyboard("Left");
m_controller->GetKey(KEY_CAM_UP).BindKeyboard("Up");
m_controller->GetKey(KEY_CAM_DOWN).BindKeyboard("Down");
m_controller->GetKey(KEY_CAM_LEFT).BindKeyboard("Left");
m_controller->GetKey(KEY_CAM_RIGHT).BindKeyboard("Right");

//Camera keyboard position switch
m_controller->GetKey(KEY_CAM_POS ).BindKeyboard("LeftShift");
m_controller->GetKey(KEY_CAM_FOV ).BindKeyboard("LeftCtrl");
m_controller->GetKey(KEY_CAM_POS).BindKeyboard("LeftShift");
m_controller->GetKey(KEY_CAM_FOV).BindKeyboard("LeftCtrl");

//Camera unzoom switch
m_controller->GetKey(KEY_CAM_RESET).BindKeyboard("Space");
@@ -251,7 +388,7 @@ void MeshViewer::Init()
m_controller->GetKey(KEY_F5).BindKeyboard("F5");
m_controller->GetKey(KEY_ESC).BindKeyboard("Escape");
}
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT


m_camera = new Camera();
@@ -282,8 +419,8 @@ void MeshViewer::Init()
//TOUKY CHANGE THAT
/*
m_ssetup->Compile("addlight 0.0 position (4 -1 -4) color (.0 .2 .5 1) "
"addlight 0.0 position (8 2 6) color #ffff "
"showgizmo true ");
"addlight 0.0 position (8 2 6) color #ffff "
"showgizmo true ");
*/
m_ssetup->Startup();
#endif //NO_SC_SETUP
@@ -295,29 +432,35 @@ void MeshViewer::Init()
}
}

void MeshViewer::TickGame(float seconds)
void MeshViewer::Unprepare()
{
WorldEntity::TickGame(seconds);
if (m_camera) g_scene->PopCamera(m_camera);
if (m_ssetup) delete m_ssetup;

if (!m_init && g_scene)
{
Init();
return;
}
MessageService::Destroy();

if (!m_init)
return;
//Register all entities
for (Entity* entity : m_entities)
Ticker::Unref(entity);

m_first_tick = true;
m_controller = nullptr;
m_camera = nullptr;
m_ssetup = nullptr;

/** ----- Init is needed ----- **/
m_init = false;
}

void MeshViewer::Update(float seconds)
{
//TODO : This should probably be "standard LoL behaviour"
#if NO_NACL_EM_INPUT
#if HAS_INPUT
{
//Shutdown logic
if (KeyReleased(KEY_ESC))
Ticker::Shutdown();
}
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT

//Compute render mesh count
float a_j = lol::abs(m_render_max[1]);
@@ -326,9 +469,9 @@ void MeshViewer::TickGame(float seconds)
m_render_max[1] = a_j * ((RATIO_WH * 1.f) / ((i_trans != 0.f)?(i_trans):(RATIO_WH))) - RATIO_HW * .3f;

//Mesh Change
#if NO_NACL_EM_INPUT
#if HAS_INPUT
m_mesh_id = clamp(m_mesh_id + ((int)KeyPressed(KEY_MESH_PREV) - (int)KeyPressed(KEY_MESH_NEXT)), 0, (int)m_meshes.Count() - 1);
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT
m_mesh_id1 = damp(m_mesh_id1, (float)m_mesh_id, .2f, seconds);

#if ALL_FEATURES
@@ -352,7 +495,7 @@ void MeshViewer::TickGame(float seconds)
bool is_hsc = false;
vec2 tmpv = vec2::zero;

#if NO_NACL_EM_INPUT
#if HAS_INPUT
is_pos = KeyDown(KEY_CAM_POS) || KeyDown(MSE_CAM_POS);
is_fov = KeyDown(KEY_CAM_FOV) || KeyDown(MSE_CAM_FOV);

@@ -369,7 +512,7 @@ void MeshViewer::TickGame(float seconds)

tmpv += vec2((float)KeyDown(KEY_CAM_UP ) - (float)KeyDown(KEY_CAM_DOWN),
(float)KeyDown(KEY_CAM_RIGHT) - (float)KeyDown(KEY_CAM_LEFT));
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT

//Base data
vec2 rot = (!is_pos && !is_fov)?(tmpv):(vec2(.0f)); rot = vec2(rot.x, -rot.y);
@@ -389,7 +532,7 @@ void MeshViewer::TickGame(float seconds)

m_rot += m_rot_speed * seconds;

#if NO_NACL_EM_INPUT
#if HAS_INPUT
if (m_reset_timer >= 0.f)
m_reset_timer -= seconds;
if (KeyPressed(KEY_CAM_RESET))
@@ -411,7 +554,7 @@ void MeshViewer::TickGame(float seconds)
m_zoom += m_zoom_speed * seconds;
m_hist_scale += m_hist_scale_speed * seconds;
}
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT

//clamp
vec2 rot_mesh = vec2(SmoothClamp(m_rot.x, -ROT_CLAMP, ROT_CLAMP, ROT_CLAMP * .1f), m_rot.y);
@@ -422,13 +565,13 @@ void MeshViewer::TickGame(float seconds)
vec2 hist_scale_mesh = vec2(SmoothClamp(m_hist_scale.x, 0.f, HST_CLAMP, HST_CLAMP * .1f),
SmoothClamp(m_hist_scale.y, 0.f, HST_CLAMP, HST_CLAMP * .1f));

#if NO_NACL_EM_INPUT
#if HAS_INPUT
if (KeyDown(KEY_CAM_RESET) && m_reset_timer < 0.f)
{
pos_mesh = vec2::zero;
zoom_mesh = 0.f;
}
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT

m_rot_mesh = vec2(damp(m_rot_mesh.x, rot_mesh.x, .2f, seconds), damp(m_rot_mesh.y, rot_mesh.y, .2f, seconds));
m_pos_mesh = vec2(damp(m_pos_mesh.x, pos_mesh.x, .2f, seconds), damp(m_pos_mesh.y, pos_mesh.y, .2f, seconds));
@@ -597,7 +740,7 @@ void MeshViewer::TickGame(float seconds)
m_ssetup->m_custom_cmd.Empty();
#endif //ALL_FEATURES

#if NACL_EM
#if HAS_WEB
/*
if (m_stream_update_time > .0f)
{
@@ -636,24 +779,23 @@ void MeshViewer::TickGame(float seconds)
#endif //WINDOWS
}

void MeshViewer::TickDraw(float seconds, Scene &scene)
void MeshViewer::Draw(float seconds, Scene &scene)
{
WorldEntity::TickDraw(seconds, scene);

if (!m_init || !m_first_tick)
return;

//TODO : This should probably be "standard LoL behaviour"
#if NO_NACL_EM_INPUT
#if HAS_INPUT
{
if (KeyReleased(KEY_F2))
Video::SetDebugRenderMode((Video::GetDebugRenderMode() + 1) % DebugRenderMode::Max);
else if (KeyReleased(KEY_F1))
Video::SetDebugRenderMode((Video::GetDebugRenderMode() + DebugRenderMode::Max - 1) % DebugRenderMode::Max);
}
#endif //NO_NACL_EM_INPUT
#endif //HAS_INPUT

#if NO_NACL_EM && WITH_TEXTURE
#if !HAS_WEB && WITH_TEXTURE
if (!m_default_texture)
{
m_texture_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinymvtexture));
@@ -662,7 +804,7 @@ void MeshViewer::TickDraw(float seconds, Scene &scene)
}
else if (m_texture && m_default_texture)
m_texture_shader->SetUniform(m_texture_uni, m_default_texture->GetTexture(), 0);
#endif //NO_NACL_EM
#endif //!HAS_WEB && WITH_TEXTURE

g_renderer->SetClearColor(m_ssetup->m_clear_color);

@@ -837,19 +979,3 @@ void MeshViewer::TickDraw(float seconds, Scene &scene)
}
#endif
}

//The basic main :
int main(int argc, char **argv)
{
System::Init(argc, argv);

Application app("MeshViewer", ivec2((int)DEFAULT_WIDTH, (int)DEFAULT_HEIGHT), 60.0f);
if (argc > 1)
new MeshViewer(argv[1]);
else
new MeshViewer();
app.Run();

return EXIT_SUCCESS;
}


+ 16
- 2
doc/samples/meshviewer/scenesetup.cpp View File

@@ -145,7 +145,7 @@ void SceneSetup::Set(SceneSetup::Display const& d, DisplayFlag const& f)
}

//-----------------------------------------------------------------------------
SceneSetupLuaObject::SceneSetupLuaObject(String& name) : LuaObjectDef()
SceneSetupLuaObject::SceneSetupLuaObject(String& name) : LuaObject()
{
m_setup = new SceneSetup(name);
SceneSetupLuaLoader::RegisterSetup(m_setup);
@@ -273,12 +273,26 @@ SceneSetupLuaLoader::SceneSetupLuaLoader() : LuaLoader()
{
LuaState* l = GetLuaState();

LuaObject::Register<SceneSetupLuaObject>(l);
LuaObjectDef::Register<SceneSetupLuaObject>(l);
}

//-----------------------------------------------------------------------------
SceneSetupLuaLoader::~SceneSetupLuaLoader() { }

//-----------------------------------------------------------------------------
static array<SceneSetupLuaObject*> g_instances;
void SceneSetupLuaLoader::Store(LuaObject* obj)
{
SceneSetupLuaObject* ezm = static_cast<SceneSetupLuaObject*>(obj);
g_instances << ezm;
}

//-----------------------------------------------------------------------------
array<SceneSetupLuaObject*>& SceneSetupLuaLoader::GetInstances()
{
return g_instances;
}

//-----------------------------------------------------------------------------
void SceneSetupLuaLoader::RegisterSetup(SceneSetup* setup)
{


+ 4
- 1
doc/samples/meshviewer/scenesetup.h View File

@@ -106,7 +106,7 @@ public:
typedef Lolua::VarEnum<SceneSetup::DisplayBase> LuaDisplay;

//-----------------------------------------------------------------------------
class SceneSetupLuaObject : public LuaObjectDef
class SceneSetupLuaObject : public LuaObject
{
typedef Lolua::VarPtr<SceneSetupLuaObject> LuaSSetupPtr;
public:
@@ -154,6 +154,9 @@ class SceneSetupLuaLoader : public LuaLoader
public:
SceneSetupLuaLoader();
virtual ~SceneSetupLuaLoader();
//Virtual Store lua object ------------------------------------------------
virtual void Store(LuaObject* obj) { }
array<SceneSetupLuaObject*>& GetInstances();

//-------------------------------------------------------------------------
protected:


+ 3
- 3
doc/tutorial/14_lol_lua.cpp View File

@@ -19,11 +19,11 @@
using namespace lol;

//-----------------------------------------------------------------------------
class DemoObject : public LuaObjectDef
class DemoObject : public LuaObject
{
typedef Lolua::VarPtr<DemoObject> LuaDemoObjectPtr;
public:
DemoObject() : LuaObjectDef() {}
DemoObject() : LuaObject() {}
virtual ~DemoObject() {}
static DemoObject* New(LuaState* l, int arg_nb)
{
@@ -103,7 +103,7 @@ public:
LuaState* l = GetLuaState();

//Registering demo object
LuaObject::Register<DemoObject>(l);
LuaObjectDef::Register<DemoObject>(l);

//Registering function
LuaFunction add_string(l, "GlobalAddString", &GlobalAddString);


+ 16
- 2
src/easymesh/easymeshlua.cpp View File

@@ -27,7 +27,7 @@ EasyMeshLuaLoader::EasyMeshLuaLoader() : LuaLoader()
LuaState* l = GetLuaState();

//Registering demo object
LuaObject::Register<EasyMeshLuaObject>(l);
LuaObjectDef::Register<EasyMeshLuaObject>(l);
}

//-----------------------------------------------------------------------------
@@ -37,7 +37,21 @@ EasyMeshLuaLoader::~EasyMeshLuaLoader()
}

//-----------------------------------------------------------------------------
EasyMeshLuaObject::EasyMeshLuaObject() : LuaObjectDef()
static array<EasyMeshLuaObject*> g_instances;
void EasyMeshLuaLoader::Store(LuaObject* obj)
{
EasyMeshLuaObject* ezm = static_cast<EasyMeshLuaObject*>(obj);
g_instances << ezm;
}

//-----------------------------------------------------------------------------
array<EasyMeshLuaObject*>& EasyMeshLuaLoader::GetInstances()
{
return g_instances;
}

//-----------------------------------------------------------------------------
EasyMeshLuaObject::EasyMeshLuaObject() : LuaObject()
{
}



+ 12
- 9
src/easymesh/easymeshlua.h View File

@@ -16,15 +16,7 @@ namespace lol
{

//-----------------------------------------------------------------------------
class EasyMeshLuaLoader : public LuaLoader
{
public:
EasyMeshLuaLoader();
virtual ~EasyMeshLuaLoader();
};

//-----------------------------------------------------------------------------
class EasyMeshLuaObject : public LuaObjectDef
class EasyMeshLuaObject : public LuaObject
{
typedef Lolua::VarPtr<EasyMeshLuaObject> EzMeshPtr;
EasyMesh m_instance;
@@ -650,4 +642,15 @@ public:

};

//-----------------------------------------------------------------------------
class EasyMeshLuaLoader : public LuaLoader
{
public:
EasyMeshLuaLoader();
virtual ~EasyMeshLuaLoader();
//Virtual Store lua object ------------------------------------------------
virtual void Store(LuaObject* obj);
array<EasyMeshLuaObject*>& GetInstances();
};

} /* namespace lol */

+ 51
- 10
src/input/controller.h View File

@@ -250,6 +250,7 @@ public:
{
return (int)(m_mouse_axis.Count() + m_joystick_axis.Count());
}
//Keys --------------------------------------------------------------------
InputProfile& operator<<(InputProfile::Keyboard const& binding)
{
m_keys.PushUnique(binding);
@@ -260,6 +261,7 @@ public:
m_keys += bindings;
return *this;
}
//------
InputProfile& operator<<(InputProfile::MouseKey const& binding)
{
m_mouse_keys.PushUnique(binding);
@@ -270,16 +272,7 @@ public:
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);
@@ -293,6 +286,18 @@ public:
m_joystick_keys += bindings;
return *this;
}
//Axis --------------------------------------------------------------------
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::JoystickAxis const& binding)
{
m_joystick.PushUnique(binding.m_joy);
@@ -306,6 +311,41 @@ public:
m_joystick_axis += bindings;
return *this;
}
//BindingType -------------------------------------------------------------
struct InputTypeBase : public StructSafeEnum
{
enum Type
{
Keyboard = 0,
MouseKey,
JoystickKey,
MouseAxis,
JoystickAxis,

MAX,
};
protected:
virtual bool BuildEnumMap(map<int64_t, String>& enum_map) { return true; }
};
typedef SafeEnum<InputTypeBase> InputType;

//Template helper ---------------------------------------------------------
template <typename T, ptrdiff_t BEGIN, ptrdiff_t END>
void AddBindings(InputType const& type, uint64_t joy = 0)
{
for (ptrdiff_t i = BEGIN; i < END; ++i)
{
switch (type.ToScalar())
{
case InputType::Keyboard:/******/*this << InputProfile::Keyboard/******/(/***/(int)i, T((int)i).ToString()); break;
case InputType::MouseKey:/******/*this << InputProfile::MouseKey/******/(/***/(int)i, T((int)i).ToString()); break;
case InputType::JoystickKey:/***/*this << InputProfile::JoystickKey/***/(joy, (int)i, T((int)i).ToString()); break;
case InputType::MouseAxis:/*****/*this << InputProfile::MouseAxis/*****/(/***/(int)i, T((int)i).ToString()); break;
case InputType::JoystickAxis:/**/*this << InputProfile::JoystickAxis/**/(joy, (int)i, T((int)i).ToString()); break;
}
}
}

private:
array<Keyboard> m_keys;
@@ -315,6 +355,7 @@ private:
array<JoystickKey> m_joystick_keys;
array<JoystickAxis> m_joystick_axis;
};
typedef InputProfile::InputType InputProfileType;

//-----------------------------------------------------------------------------
//TODO: Add mask|layer system to prevent several controllers from interfering with another. (input overlay in menus)


+ 1
- 1
src/input/input.cpp View File

@@ -97,7 +97,7 @@ InputDeviceInternal* InputDeviceInternal::CreateStandardMouse()
mouse->AddKey(g_name_mouse_key_middle.C());
mouse->AddKey(g_name_mouse_key_right.C());
//Added to manage if mouse is in the screen or not.
mouse->AddKey(g_name_mouse_key_inScreen.C());
mouse->AddKey(g_name_mouse_key_in_screen.C());

mouse->AddAxis(g_name_mouse_axis_x.C());
mouse->AddAxis(g_name_mouse_axis_y.C());


+ 1
- 1
src/input/input.h View File

@@ -28,7 +28,7 @@ static String g_name_joystick(const uint64_t num)
const String g_name_mouse_key_left("Left");
const String g_name_mouse_key_middle("Middle");
const String g_name_mouse_key_right("Right");
const String g_name_mouse_key_inScreen("InScreen");
const String g_name_mouse_key_in_screen("InScreen");
const String g_name_mouse_axis_x("X");
const String g_name_mouse_axis_y("Y");
const String g_name_mouse_axis_xpixel("XPixel");


+ 10
- 9
src/lol/sys/thread.h View File

@@ -71,20 +71,20 @@ struct ThreadJobTypeBase : public StructSafeEnum
{
NONE,
WORK_TODO,
WORK_DONE,
WORK_SUCCESSED,
WORK_FAILED,
WORK_FETCHED,
WORK_DONE,
THREAD_STOP
};
protected:
virtual bool BuildEnumMap(map<int64_t, String>& enum_map)
{
enum_map[NONE] = "NONE";
enum_map[WORK_TODO] = "WORK_TODO";
enum_map[WORK_DONE] = "WORK_DONE";
enum_map[WORK_FAILED] = "WORK_FAILED";
enum_map[WORK_FETCHED] = "WORK_FETCHED";
enum_map[THREAD_STOP] = "THREAD_STOP";
enum_map[NONE] = "NONE";
enum_map[WORK_TODO] = "WORK_TODO";
enum_map[WORK_SUCCESSED] = "WORK_SUCCESSED";
enum_map[WORK_FAILED] = "WORK_FAILED";
enum_map[WORK_DONE] = "WORK_DONE";
enum_map[THREAD_STOP] = "THREAD_STOP";
return true;
}
};
@@ -95,9 +95,10 @@ class ThreadJob
{
friend class BaseThreadManager;

protected:
inline ThreadJob(ThreadJobType type) : m_type(type) {}
public:
inline ThreadJob() : m_type(ThreadJobType::NONE) {}
inline ThreadJob(ThreadJobType type) : m_type(type) {}
virtual ~ThreadJob() {}

ThreadJobType GetJobType() { return m_type; }


+ 49
- 100
src/lol/sys/threadtypes.h View File

@@ -34,7 +34,7 @@ public:
{ }

//Work stuff
bool AddJob(ThreadJob* job);
bool AddWork(ThreadJob* job);
bool GetWorkResult(array<ThreadJob*>& results);

protected:
@@ -42,84 +42,71 @@ protected:
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;
};

//FileUpdateTester ------------------------------------------------------------
//Test the files registered and warns when they update
class FileUpdateTester : public BaseThreadManager
{
typedef BaseThreadManager super;
public:
struct Status
class Status
{
protected:
mutex m_mutex;
long int m_time = 0;
bool m_updated = false;
public:
void SetTime(long int time)
{
m_mutex.lock();
m_time = time;
m_mutex.unlock();
}
long int GetTime()
{
m_mutex.lock();
long int time = m_time;
m_mutex.unlock();
return m_time;
}
void SetUpdated(bool updated)
{
m_mutex.lock();
m_updated = updated;
m_mutex.unlock();
}
bool HasUpdated()
{
m_mutex.lock();
bool updated = m_updated;
m_mutex.unlock();
return updated;
}
};
public:
char const *GetName() { return "<FileUpdateTester>"; }
FileUpdateTester() : BaseThreadManager(1) { }
~FileUpdateTester() { }
FileUpdateTester(uint32_t frame_skip = 4)
: BaseThreadManager(1)
{ m_frame_skip = frame_skip; }
virtual ~FileUpdateTester();

//-------------------------------------------------------------------------
FileUpdateTester::Status* RegisterFile(String const& path);
protected:
void UnregisterFile(String const& path);
public:
void UnregisterFile(FileUpdateTester::Status*& status);
//TODO: Add directories
//FileUpdateTester::Status* RegisterDirectory(String const& path, bool check_files=false);
virtual void TickGame(float seconds);
virtual void TreatResult(ThreadJob* result);

private:
uint32_t m_frame_skip = 4;
uint32_t m_frame_count = 0;
array<ThreadJob*> m_job_done;
map<String, Status*> m_files;
};

//AsyncImageJob ---------------------------------------------------------------
class AsyncImageJob : public ThreadJob
{
public:
AsyncImageJob()
: ThreadJob(ThreadJobType::NONE)
{
m_path = String();
}
AsyncImageJob(String path)
: ThreadJob(ThreadJobType::WORK_TODO)
{
m_path = path;
}
String const& GetPath() { return m_path; }
Image const& GetImage() { return m_image; }

protected:
virtual bool DoWork()
{
return m_image.Load(m_path.C());
}

String m_path;
Image m_image;
};
typedef FileUpdateTester::Status FileUpdateStatus;

//AsyncImageLoader ------------------------------------------------------------
//Load images asynchronously, automatically updating the dummy image
@@ -132,53 +119,15 @@ public:
{
m_dummy_image.DummyFill();
}
~AsyncImageLoader()
virtual ~AsyncImageLoader()
{ }

//Returns a dummy image, and start a job to load the image on a thread
Image* Load(const lol::String& path)
{
//Create a job
AsyncImageJob* job = new AsyncImageJob(path);
//Create a dummy image
Image* image = new Image(m_dummy_image);
//Link the two
m_images[path] = image;
//Add job
AddWork(job);
//return Dummy image
return image;
}
bool CheckStatus(Image* image)
{
if (m_loaded_images.find(image) != INDEX_NONE)
{
m_loaded_images.remove_item(image);
return true;
}
return false;
}
Image* Load(const lol::String& path);
bool CheckStatus(Image* image);

protected:
virtual void TreatResult(ThreadJob* result)
{
AsyncImageJob* job = dynamic_cast<AsyncImageJob*>(result);
ASSERT(job);
//Copy image if work is OK
if (job->GetJobType() != ThreadJobType::WORK_FAILED)
{
Image* src = m_images[job->GetPath()];
m_images.remove(job->GetPath());
src->Copy(job->GetImage());
m_loaded_images.PushUnique(src);
}
else
{
Log::Error("AsyncImageJob FAILED. See load image error above.\n");
}
//Delete all that
delete(result);
}
virtual void TreatResult(ThreadJob* result);

private:
Image m_dummy_image;


+ 4
- 2
src/lolimgui.cpp View File

@@ -63,8 +63,10 @@ LolImGui::LolImGui()
<< ShaderProgram::Pixel << imgui_pixel;

//Input Setup -------------------------------------------------------------
for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i)
m_profile << InputProfile::Keyboard(i, LolImGuiKey(i).ToString());
InputProfile& ip = m_profile;
ip.AddBindings<LolImGuiKey, LolImGuiKey::KEY_START, LolImGuiKey::KEY_END>(InputProfileType::Keyboard);
//for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i)
// m_profile << InputProfile::Keyboard(i, LolImGuiKey(i).ToString());
for (int i = LolImGuiKey::MOUSE_KEY_START; i < LolImGuiKey::MOUSE_KEY_END; ++i)
m_profile << InputProfile::MouseKey(i, LolImGuiKey(i).ToString());



+ 1
- 2
src/lolimgui.h View File

@@ -96,6 +96,7 @@ class LolImGui : public Entity
enum_map[LeftClick] = g_name_mouse_key_left;
enum_map[RightClick] = g_name_mouse_key_right;
enum_map[MiddleClick] = g_name_mouse_key_middle;
enum_map[Focus] = g_name_mouse_key_in_screen;

return true;
}
@@ -125,8 +126,6 @@ class LolImGui : public Entity
};
typedef SafeEnum<LolImGuiAxisBase> LolImGuiAxis;



public:
//-------------------------------------------------------------------------
LolImGui();


+ 40
- 0
src/lolua/baselua.cpp View File

@@ -25,6 +25,7 @@ class LuaBaseData
{
friend class Lolua::Loader;

//PANIC PANIC -------------------------------------------------------------
static int LuaPanic(LuaState* l)
{
char const *message = lua_tostring(l, -1);
@@ -33,11 +34,13 @@ class LuaBaseData
return 0;
}

//Exec lua code -----------------------------------------------------------
static int LuaDoCode(LuaState *l, String const& s)
{
return luaL_dostring(l, s.C());
}

//Open a file and exec lua code -------------------------------------------
static int LuaDoFile(LuaState *l)
{
if (lua_isnoneornil(l, 1))
@@ -90,14 +93,51 @@ Loader::Loader()

/* Override dofile() */
LuaFunction do_file(m_lua_state, "dofile", LuaBaseData::LuaDoFile);

//Store this instance
Loader::Store(m_lua_state, this);
}

//-----------------------------------------------------------------------------
Loader::~Loader()
{
//Release this instance
Loader::Store(m_lua_state, this);

lua_close(m_lua_state);
}

//Store loader ------------------------------------------------------------
static array<LuaState*, Lolua::Loader*> g_loaders;
void Loader::Store(LuaState* l, Lolua::Loader* loader)
{
g_loaders.push(l, loader);
}
void Loader::Release(LuaState* l, Lolua::Loader* loader)
{
for (ptrdiff_t i = 0; i < g_loaders.count(); ++i)
{
if (g_loaders[i].m1 == l && g_loaders[i].m2 == loader)
{
g_loaders.remove(i);
return;
}
}
}

//Store lua object --------------------------------------------------------
void Loader::StoreObject(LuaState* l, Object* obj)
{
for (ptrdiff_t i = 0; i < g_loaders.count(); ++i)
{
if (g_loaders[i].m1 == l)
{
g_loaders[i].m2->Store(obj);
return;
}
}
}

//-----------------------------------------------------------------------------
bool Loader::ExecLuaFile(String const &lua)
{


+ 41
- 24
src/lolua/baselua.h View File

@@ -96,12 +96,12 @@ struct ObjectLib
};

//-----------------------------------------------------------------------------
class ObjectDef
class Object
{
public:
ObjectDef() { }
virtual ~ObjectDef() { }
static ObjectDef* New(LuaState* l, int arg_nb)
Object() { }
virtual ~Object() { }
static Object* New(LuaState* l, int arg_nb)
{
UNUSED(l);
UNUSED(arg_nb);
@@ -114,12 +114,12 @@ public:
//-----------------------------------------------------------------------------
// Class available to link C++ class to Lua methods
//--
class Object
class ObjectDef
{
public:
//-------------------------------------------------------------------------
Object() { }
virtual ~Object() { }
ObjectDef() { }
virtual ~ObjectDef() { }

//-------------------------------------------------------------------------
template <typename TLuaClass>
@@ -129,6 +129,7 @@ public:
static const luaL_Reg default_statics[]
{
{ "New", New<TLuaClass> },
{ "Store", Store<TLuaClass> },
{ "__gc", Del<TLuaClass> },
{ NULL, NULL }
};
@@ -227,6 +228,7 @@ protected:
}

//-------------------------------------------------------------------------
template <typename TLuaClass> static int Store(LuaState * l);
template <typename TLuaClass> static int Del(LuaState * l);
};

@@ -305,7 +307,7 @@ protected:
}
virtual void InnerGet(LuaState* l, int& index)
{
T** obj = static_cast<T**>(luaL_checkudata(l, index++, Object::GetMethodName<T>()));
T** obj = static_cast<T**>(luaL_checkudata(l, index++, ObjectDef::GetMethodName<T>()));
m_value = obj ? *obj : nullptr;
}
void InnerPush(LuaState* l)
@@ -315,20 +317,6 @@ protected:
}
};

//
// Object member implementations that require VarPtr
//

template <typename TLuaClass>
int Object::Del(LuaState * l)
{
VarPtr<TLuaClass> obj;
obj.Get(l, 1);
ASSERT(obj());
delete obj();
return 0;
}

//-----------------------------------------------------------------------------
/* TODO: FIX THAT TOUKY !!
template<typename T>
@@ -342,7 +330,7 @@ public:
protected:
virtual void InnerGet(LuaState* l, int& index)
{
T** obj = static_cast<T**>(luaL_testudata(l, index++, Object::GetMethodName<T>()));
T** obj = static_cast<T**>(luaL_testudata(l, index++, ObjectDef::GetMethodName<T>()));
m_value = obj ? *obj : nullptr;
}
};
@@ -939,6 +927,7 @@ private:
//-----------------------------------------------------------------------------
class Loader
{
friend class ObjectDef;
public:
Loader();
virtual ~Loader();
@@ -965,16 +954,44 @@ public:

protected:
LuaState* GetLuaState();
static void Store(LuaState* l, Loader* loader);
static void Release(LuaState* l, Loader* loader);
static void StoreObject(LuaState* l, Object* obj);
//Virtual Store lua object ------------------------------------------------
virtual void Store(Object* obj) { }

private:
LuaState* m_lua_state;
};

//-----------------------------------------------------------------------------
// ObjectDef member implementations that require VarPtr

template <typename TLuaClass>
int ObjectDef::Store(LuaState * l)
{
VarPtr<TLuaClass> obj;
obj.Get(l, 1);
ASSERT(obj());
Loader::StoreObject(l, obj());
return 0;
}

template <typename TLuaClass>
int ObjectDef::Del(LuaState * l)
{
VarPtr<TLuaClass> obj;
obj.Get(l, 1);
ASSERT(obj());
delete obj();
return 0;
}

} /* namespace Lolua */

typedef Lolua::Function LuaFunction;
typedef Lolua::Object LuaObject;
typedef Lolua::ObjectDef LuaObjectDef;
typedef Lolua::Object LuaObject;
typedef Lolua::ObjectLib LuaObjectLib;
typedef Lolua::Loader LuaLoader;
typedef Lolua::Var<bool> LuaBool;


+ 1
- 3
src/sys/thread.cpp View File

@@ -129,7 +129,7 @@ void BaseThreadManager::BaseThreadWork()
else if (*job == ThreadJobType::WORK_TODO)
{
if (job->DoWork())
job->SetJobType(ThreadJobType::WORK_DONE);
job->SetJobType(ThreadJobType::WORK_SUCCESSED);
else
job->SetJobType(ThreadJobType::WORK_FAILED);
m_resultqueue.push(job);
@@ -165,8 +165,6 @@ void BaseThreadManager::TickGame(float seconds)
for (int i = 0; i < result.count(); i++)
{
ThreadJob* job = result[i];
if (job->GetJobType() == ThreadJobType::WORK_DONE)
job->SetJobType(ThreadJobType::WORK_FETCHED);
TreatResult(job);
}
}


+ 156
- 17
src/sys/threadtypes.cpp View File

@@ -16,7 +16,7 @@
using namespace lol;

//DefaultThreadManager --------------------------------------------------------
bool DefaultThreadManager::AddJob(ThreadJob* job)
bool DefaultThreadManager::AddWork(ThreadJob* job)
{
return AddWork(job);
}
@@ -28,24 +28,57 @@ bool DefaultThreadManager::GetWorkResult(array<ThreadJob*>& results)
}

//FileUpdateTesterJob ---------------------------------------------------------
bool FileUpdateTesterJob::DoWork()
class FileUpdateTesterJob : public ThreadJob
{
File f;
f.Open(m_path, FileAccess::Read);
if (!f.IsValid())
return false;
if (!m_ready)
m_time = f.GetModificationTime();
else
friend class FileUpdateTester;
public:
FileUpdateTesterJob()
: ThreadJob(ThreadJobType::NONE) { }
FileUpdateTesterJob(String path)
: ThreadJob(ThreadJobType::WORK_TODO)
{
long int new_time = f.GetModificationTime();
if (new_time > m_time)
m_updated = true;
m_path = path;
}
return true;
}
String& GetPath() { return m_path; }
bool HasUpdated() { return m_updated; }
void Restart()
{
SetJobType(ThreadJobType::WORK_TODO);
m_updated = false;
}

protected:
virtual bool 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;
}

//-----------------
bool m_ready = false;
String m_path = String();
long int m_time = 0;
bool m_updated = false;
};

//FileUpdateTester ------------------------------------------------------------
FileUpdateTester::~FileUpdateTester()
{
ASSERT(!m_files.count(), "Files need to be unregistered before destroying FileUpdateTester");
}

//File interface --------------------------------------------------------------
FileUpdateTester::Status* FileUpdateTester::RegisterFile(String const& path)
{
m_job_dispatch << new FileUpdateTesterJob(path);
@@ -53,26 +86,132 @@ FileUpdateTester::Status* FileUpdateTester::RegisterFile(String const& path)
return m_files[path];
}

//-------------------------------------------------------------------------
void FileUpdateTester::UnregisterFile(String const& path)
{
ASSERT(m_files.has_key(path));
delete m_files[path];
m_files.remove(path);
}

void FileUpdateTester::UnregisterFile(FileUpdateTester::Status*& status)
{
ASSERT(status);
array<String> keys = m_files.keys();
for (String key : keys)
{
if (m_files[key] == status)
{
UnregisterFile(key);
status = nullptr;
return;
}
}
ASSERT(false, "Status wasn't found");
}

//-----------------------------------------------------------------------------
void FileUpdateTester::TickGame(float seconds)
{
super::TickGame(seconds);

if (!m_job_dispatch.count() && m_job_done.count())
{
if (m_frame_count++ < m_frame_skip)
return;
m_frame_count = 0;

array<String> keys = m_files.keys();
for (String key : keys)
m_files[key]->SetUpdated(false);

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;
m_files[job->GetPath()]->SetTime(job->m_time);
m_files[job->GetPath()]->SetUpdated(true);
job->Restart();
m_job_done << job;
}
}

//AsyncImageJob ---------------------------------------------------------------
class AsyncImageJob : public ThreadJob
{
public:
AsyncImageJob()
: ThreadJob(ThreadJobType::NONE)
{
m_path = String();
}
AsyncImageJob(String path)
: ThreadJob(ThreadJobType::WORK_TODO)
{
m_path = path;
}
String const& GetPath() { return m_path; }
Image const& GetImage() { return m_image; }

protected:
virtual bool DoWork()
{
return m_image.Load(m_path.C());
}

String m_path;
Image m_image;
};

//-----------------------------------------------------------------------------
Image* AsyncImageLoader::Load(const lol::String& path)
{
//Create a job
AsyncImageJob* job = new AsyncImageJob(path);
//Create a dummy image
Image* image = new Image(m_dummy_image);
//Link the two
m_images[path] = image;
//Add job
AddWork(job);
//return Dummy image
return image;
}

//-----------------------------------------------------------------------------
bool AsyncImageLoader::CheckStatus(Image* image)
{
if (m_loaded_images.find(image) != INDEX_NONE)
{
m_loaded_images.remove_item(image);
return true;
}
return false;
}

//-----------------------------------------------------------------------------
void AsyncImageLoader::TreatResult(ThreadJob* result)
{
AsyncImageJob* job = dynamic_cast<AsyncImageJob*>(result);
ASSERT(job);
//Copy image if work is OK
if (job->GetJobType() == ThreadJobType::WORK_SUCCESSED)
{
Image* src = m_images[job->GetPath()];
m_images.remove(job->GetPath());
src->Copy(job->GetImage());
m_loaded_images.PushUnique(src);
}
else
{
Log::Error("AsyncImageJob FAILED. See load image error above.\n");
}
//Delete all that
delete(result);
}

Loading…
Cancel
Save