From 3f167f2f1d32bfb7ed9e5931ec22c0418ed2ee38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Sat, 28 Mar 2015 19:59:13 +0000 Subject: [PATCH] ImGui 1.37 MeshViewer first pass --- build/lol-build | 2 +- build/msbuild/lol.vars.props | 2 +- configure.ac | 2 +- ...iewer_init.lua => meshviewer.easymesh.lua} | 0 doc/samples/meshviewer.vcxproj | 4 +- doc/samples/meshviewer/meshviewer.cpp | 352 ++++++++++++------ doc/samples/meshviewer/scenesetup.cpp | 18 +- doc/samples/meshviewer/scenesetup.h | 5 +- doc/tutorial/14_lol_lua.cpp | 6 +- src/easymesh/easymeshlua.cpp | 18 +- src/easymesh/easymeshlua.h | 21 +- src/input/controller.h | 61 ++- src/input/input.cpp | 2 +- src/input/input.h | 2 +- src/lol/sys/thread.h | 19 +- src/lol/sys/threadtypes.h | 149 +++----- src/lolimgui.cpp | 6 +- src/lolimgui.h | 3 +- src/lolua/baselua.cpp | 40 ++ src/lolua/baselua.h | 65 ++-- src/sys/thread.cpp | 4 +- src/sys/threadtypes.cpp | 173 ++++++++- 22 files changed, 650 insertions(+), 304 deletions(-) rename doc/samples/data/{meshviewer_init.lua => meshviewer.easymesh.lua} (100%) diff --git a/build/lol-build b/build/lol-build index e8e5f9d2..b6e2deb4 100755 --- a/build/lol-build +++ b/build/lol-build @@ -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" diff --git a/build/msbuild/lol.vars.props b/build/msbuild/lol.vars.props index e33baacd..9afda655 100644 --- a/build/msbuild/lol.vars.props +++ b/build/msbuild/lol.vars.props @@ -9,7 +9,7 @@ $(PegtlDir)\include - $(ExternalDir)\imgui-1.36 + $(ExternalDir)\imgui-1.37 $(ImguiDir) diff --git a/configure.ac b/configure.ac index 1fdfc673..561818e0 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/samples/data/meshviewer_init.lua b/doc/samples/data/meshviewer.easymesh.lua similarity index 100% rename from doc/samples/data/meshviewer_init.lua rename to doc/samples/data/meshviewer.easymesh.lua diff --git a/doc/samples/meshviewer.vcxproj b/doc/samples/meshviewer.vcxproj index fdcf55c9..d757c912 100644 --- a/doc/samples/meshviewer.vcxproj +++ b/doc/samples/meshviewer.vcxproj @@ -54,10 +54,10 @@ true true - + true - + true diff --git a/doc/samples/meshviewer/meshviewer.cpp b/doc/samples/meshviewer/meshviewer.cpp index 6a7667a7..37050588 100644 --- a/doc/samples/meshviewer/meshviewer.cpp +++ b/doc/samples/meshviewer/meshviewer.cpp @@ -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 m_targets; }; -MeshViewer::MeshViewer(char const *file_name = "data/mesh-buffer.txt") +//EasyMeshLoadJob ------------------------------------------------------------- +bool EasyMeshLoadJob::DoWork() +{ + if (m_loader.ExecLuaFile(m_path)) + { + array& 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(InputProfileType::Keyboard); + ip.AddBindings(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 result; + m_file_loader->GetWorkResult(result); + if (result.count()) + { + for (ThreadJob* job : result) + { + if (job->GetJobType() == ThreadJobType::WORK_SUCCESSED) + { + MeshViewerLoadJob* mvjob = static_cast(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<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<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; -} - diff --git a/doc/samples/meshviewer/scenesetup.cpp b/doc/samples/meshviewer/scenesetup.cpp index d38fc7f1..45718e54 100644 --- a/doc/samples/meshviewer/scenesetup.cpp +++ b/doc/samples/meshviewer/scenesetup.cpp @@ -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(l); + LuaObjectDef::Register(l); } //----------------------------------------------------------------------------- SceneSetupLuaLoader::~SceneSetupLuaLoader() { } +//----------------------------------------------------------------------------- +static array g_instances; +void SceneSetupLuaLoader::Store(LuaObject* obj) +{ + SceneSetupLuaObject* ezm = static_cast(obj); + g_instances << ezm; +} + +//----------------------------------------------------------------------------- +array& SceneSetupLuaLoader::GetInstances() +{ + return g_instances; +} + //----------------------------------------------------------------------------- void SceneSetupLuaLoader::RegisterSetup(SceneSetup* setup) { diff --git a/doc/samples/meshviewer/scenesetup.h b/doc/samples/meshviewer/scenesetup.h index 9a352305..d5008579 100644 --- a/doc/samples/meshviewer/scenesetup.h +++ b/doc/samples/meshviewer/scenesetup.h @@ -106,7 +106,7 @@ public: typedef Lolua::VarEnum LuaDisplay; //----------------------------------------------------------------------------- -class SceneSetupLuaObject : public LuaObjectDef +class SceneSetupLuaObject : public LuaObject { typedef Lolua::VarPtr LuaSSetupPtr; public: @@ -154,6 +154,9 @@ class SceneSetupLuaLoader : public LuaLoader public: SceneSetupLuaLoader(); virtual ~SceneSetupLuaLoader(); + //Virtual Store lua object ------------------------------------------------ + virtual void Store(LuaObject* obj) { } + array& GetInstances(); //------------------------------------------------------------------------- protected: diff --git a/doc/tutorial/14_lol_lua.cpp b/doc/tutorial/14_lol_lua.cpp index 97d1805b..8355c52e 100644 --- a/doc/tutorial/14_lol_lua.cpp +++ b/doc/tutorial/14_lol_lua.cpp @@ -19,11 +19,11 @@ using namespace lol; //----------------------------------------------------------------------------- -class DemoObject : public LuaObjectDef +class DemoObject : public LuaObject { typedef Lolua::VarPtr 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(l); + LuaObjectDef::Register(l); //Registering function LuaFunction add_string(l, "GlobalAddString", &GlobalAddString); diff --git a/src/easymesh/easymeshlua.cpp b/src/easymesh/easymeshlua.cpp index 0a741cce..7b8235f9 100644 --- a/src/easymesh/easymeshlua.cpp +++ b/src/easymesh/easymeshlua.cpp @@ -27,7 +27,7 @@ EasyMeshLuaLoader::EasyMeshLuaLoader() : LuaLoader() LuaState* l = GetLuaState(); //Registering demo object - LuaObject::Register(l); + LuaObjectDef::Register(l); } //----------------------------------------------------------------------------- @@ -37,7 +37,21 @@ EasyMeshLuaLoader::~EasyMeshLuaLoader() } //----------------------------------------------------------------------------- -EasyMeshLuaObject::EasyMeshLuaObject() : LuaObjectDef() +static array g_instances; +void EasyMeshLuaLoader::Store(LuaObject* obj) +{ + EasyMeshLuaObject* ezm = static_cast(obj); + g_instances << ezm; +} + +//----------------------------------------------------------------------------- +array& EasyMeshLuaLoader::GetInstances() +{ + return g_instances; +} + +//----------------------------------------------------------------------------- +EasyMeshLuaObject::EasyMeshLuaObject() : LuaObject() { } diff --git a/src/easymesh/easymeshlua.h b/src/easymesh/easymeshlua.h index 0408277d..a18d3b96 100644 --- a/src/easymesh/easymeshlua.h +++ b/src/easymesh/easymeshlua.h @@ -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 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& GetInstances(); +}; + } /* namespace lol */ diff --git a/src/input/controller.h b/src/input/controller.h index 6e9e99c7..7c6cac93 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -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 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 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& enum_map) { return true; } + }; + typedef SafeEnum InputType; + + //Template helper --------------------------------------------------------- + template + 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 m_keys; @@ -315,6 +355,7 @@ private: array m_joystick_keys; array m_joystick_axis; }; +typedef InputProfile::InputType InputProfileType; //----------------------------------------------------------------------------- //TODO: Add mask|layer system to prevent several controllers from interfering with another. (input overlay in menus) diff --git a/src/input/input.cpp b/src/input/input.cpp index 7b0c0ff6..0c736a05 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -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()); diff --git a/src/input/input.h b/src/input/input.h index 414edd5e..e66e5cad 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -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"); diff --git a/src/lol/sys/thread.h b/src/lol/sys/thread.h index e32d34b4..1769d35f 100644 --- a/src/lol/sys/thread.h +++ b/src/lol/sys/thread.h @@ -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& 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; } diff --git a/src/lol/sys/threadtypes.h b/src/lol/sys/threadtypes.h index e3469c02..d29a714a 100644 --- a/src/lol/sys/threadtypes.h +++ b/src/lol/sys/threadtypes.h @@ -34,7 +34,7 @@ public: { } //Work stuff - bool AddJob(ThreadJob* job); + bool AddWork(ThreadJob* job); bool GetWorkResult(array& results); protected: @@ -42,84 +42,71 @@ protected: array m_job_result; }; -//FileUpdateTesterJob --------------------------------------------------------- -class FileUpdateTesterJob : public ThreadJob -{ -public: - FileUpdateTesterJob() - : ThreadJob(ThreadJobType::NONE) { } - FileUpdateTesterJob(String path) - : ThreadJob(ThreadJobType::WORK_TODO) - { m_path = path; } - String& GetPath() { return m_path; } - bool HasUpdated() { return m_updated; } - void Restart() - { - SetJobType(ThreadJobType::WORK_TODO); - m_updated = false; - } - -protected: - virtual bool DoWork(); - - //----------------- - bool m_ready = false; - String m_path = String(); - long int m_time = 0; - bool m_updated = false; -}; - //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() : 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 m_job_done; map 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(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; diff --git a/src/lolimgui.cpp b/src/lolimgui.cpp index 8966d52c..e0185c93 100644 --- a/src/lolimgui.cpp +++ b/src/lolimgui.cpp @@ -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(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()); diff --git a/src/lolimgui.h b/src/lolimgui.h index 545bbdf8..7befa1b4 100644 --- a/src/lolimgui.h +++ b/src/lolimgui.h @@ -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 LolImGuiAxis; - - public: //------------------------------------------------------------------------- LolImGui(); diff --git a/src/lolua/baselua.cpp b/src/lolua/baselua.cpp index 03453040..8c5c5163 100644 --- a/src/lolua/baselua.cpp +++ b/src/lolua/baselua.cpp @@ -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 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) { diff --git a/src/lolua/baselua.h b/src/lolua/baselua.h index 46e8cb13..716f4ab9 100644 --- a/src/lolua/baselua.h +++ b/src/lolua/baselua.h @@ -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 @@ -129,6 +129,7 @@ public: static const luaL_Reg default_statics[] { { "New", New }, + { "Store", Store }, { "__gc", Del }, { NULL, NULL } }; @@ -227,6 +228,7 @@ protected: } //------------------------------------------------------------------------- + template static int Store(LuaState * l); template static int Del(LuaState * l); }; @@ -305,7 +307,7 @@ protected: } virtual void InnerGet(LuaState* l, int& index) { - T** obj = static_cast(luaL_checkudata(l, index++, Object::GetMethodName())); + T** obj = static_cast(luaL_checkudata(l, index++, ObjectDef::GetMethodName())); m_value = obj ? *obj : nullptr; } void InnerPush(LuaState* l) @@ -315,20 +317,6 @@ protected: } }; -// -// Object member implementations that require VarPtr -// - -template -int Object::Del(LuaState * l) -{ - VarPtr obj; - obj.Get(l, 1); - ASSERT(obj()); - delete obj(); - return 0; -} - //----------------------------------------------------------------------------- /* TODO: FIX THAT TOUKY !! template @@ -342,7 +330,7 @@ public: protected: virtual void InnerGet(LuaState* l, int& index) { - T** obj = static_cast(luaL_testudata(l, index++, Object::GetMethodName())); + T** obj = static_cast(luaL_testudata(l, index++, ObjectDef::GetMethodName())); 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 +int ObjectDef::Store(LuaState * l) +{ + VarPtr obj; + obj.Get(l, 1); + ASSERT(obj()); + Loader::StoreObject(l, obj()); + return 0; +} + +template +int ObjectDef::Del(LuaState * l) +{ + VarPtr 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 LuaBool; diff --git a/src/sys/thread.cpp b/src/sys/thread.cpp index 3ccf1a8a..1c71f4c8 100644 --- a/src/sys/thread.cpp +++ b/src/sys/thread.cpp @@ -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); } } diff --git a/src/sys/threadtypes.cpp b/src/sys/threadtypes.cpp index f3f9675e..86471c32 100644 --- a/src/sys/threadtypes.cpp +++ b/src/sys/threadtypes.cpp @@ -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& 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 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 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(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(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); +}