| @@ -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" | |||
| @@ -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) --> | |||
| @@ -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 | |||
| @@ -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"> | |||
| @@ -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; | |||
| } | |||
| @@ -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) | |||
| { | |||
| @@ -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: | |||
| @@ -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); | |||
| @@ -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() | |||
| { | |||
| } | |||
| @@ -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 */ | |||
| @@ -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) | |||
| @@ -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()); | |||
| @@ -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"); | |||
| @@ -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; } | |||
| @@ -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; | |||
| @@ -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()); | |||
| @@ -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(); | |||
| @@ -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) | |||
| { | |||
| @@ -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; | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||