Skip to content

Commit

Permalink
Adding autoreload using dmon
Browse files Browse the repository at this point in the history
  • Loading branch information
mwestphal committed Mar 17, 2024
1 parent 6c8d6e3 commit f73f8df
Show file tree
Hide file tree
Showing 5 changed files with 1,881 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ option(F3D_MODULE_EXR "OpenEXR images module" OFF)
# Use externals
option(F3D_USE_EXTERNAL_CXXOPTS "Use external cxxopts dependency" OFF)
option(F3D_USE_EXTERNAL_NLOHMANN_JSON "Use external nlohmann_json dependency" OFF)
option(F3D_USE_EXTERNAL_DMON "Use external dmon dependency" OFF)

if (F3D_USE_EXTERNAL_CXXOPTS)
find_package(cxxopts REQUIRED)
endif ()
if (F3D_USE_EXTERNAL_NLOHMANN_JSON)
find_package(nlohmann_json REQUIRED)
endif ()
if (F3D_USE_EXTERNAL_DMON)
find_package(dmon REQUIRED)
endif ()

# VTK dependency
# Optional components should list VTK modules
Expand Down
7 changes: 7 additions & 0 deletions application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ elseif (MSVC)
endif ()

target_include_directories(f3d PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

if (F3D_USE_EXTERNAL_CXXOPTS)
target_link_libraries(f3d PRIVATE cxxopts::cxxopts)
else ()
Expand All @@ -69,6 +70,12 @@ else ()
target_include_directories(f3d PUBLIC $<BUILD_INTERFACE:${F3D_SOURCE_DIR}/external/nlohmann_json>)
endif ()

if (F3D_USE_EXTERNAL_DMON)
target_link_libraries(f3d PRIVATE dmon::dmon)
else ()
target_include_directories(f3d PUBLIC $<BUILD_INTERFACE:${F3D_SOURCE_DIR}/external/dmon>)
endif ()

set(f3d_compile_options_private "")
set(f3d_compile_options_public "")
set(f3d_link_options_public "")
Expand Down
142 changes: 107 additions & 35 deletions application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
#include "F3DOptionsParser.h"
#include "F3DSystemTools.h"

#define DMON_IMPL
#include "dmon.h"

#include "engine.h"
#include "interactor.h"
#include "log.h"
#include "options.h"
#include "window.h"

#include <algorithm>
#include <atomic>
#include <cassert>
#include <filesystem>
#include <mutex>
#include <set>

namespace fs = std::filesystem;
Expand Down Expand Up @@ -132,15 +137,36 @@ class F3DStarter::F3DInternals
}
}

static void dmonFolderChanged(dmon_watch_id watch_id, dmon_action action, const char* rootdir,

Check warning on line 140 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L140

Added line #L140 was not covered by tests
const char* filename, const char*, void* userData)
{
F3DStarter* self = reinterpret_cast<F3DStarter*>(userData);
self->Internals->FilesListMutex.lock();
fs::path filePath = self->Internals->FilesList[self->Internals->CurrentFileIndex];
self->Internals->FilesListMutex.unlock();
if (filePath.filename().string() == std::string(filename))

Check warning on line 147 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L143-L147

Added lines #L143 - L147 were not covered by tests
{
self->Internals->ReloadFile = true;

Check warning on line 149 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L149

Added line #L149 was not covered by tests
}
}

Check warning on line 151 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L151

Added line #L151 was not covered by tests

F3DOptionsParser Parser;
F3DAppOptions AppOptions;
f3d::options DynamicOptions;
f3d::options FileOptions;
std::unique_ptr<f3d::engine> Engine;
std::vector<fs::path> FilesList;
int CurrentFileIndex = -1;
dmon_watch_id FolderWatchId;
bool LoadedFile = false;
bool UpdateWithCommandLineParsing = true;

// dmon used atomic and mutex
std::atomic<int> CurrentFileIndex = -1;
std::mutex FilesListMutex;

// Event loop atomics
std::atomic<bool> SoftRender = false;
std::atomic<bool> ReloadFile = false;
};

//----------------------------------------------------------------------------
Expand All @@ -150,10 +176,17 @@ F3DStarter::F3DStarter()
// Set option outside of command line and config file
this->Internals->DynamicOptions.set(
"ui.dropzone-info", "Drop a file or HDRI to load it\nPress H to show cheatsheet");

// Initialize dmon
dmon_init();
}

//----------------------------------------------------------------------------
F3DStarter::~F3DStarter() = default;
F3DStarter::~F3DStarter()
{
// deinit dmon
dmon_deinit();
}

//----------------------------------------------------------------------------
int F3DStarter::Start(int argc, char** argv)
Expand Down Expand Up @@ -210,41 +243,17 @@ int F3DStarter::Start(int argc, char** argv)
interactor.setKeyPressCallBack(
[this](int, const std::string& keySym) -> bool
{
const auto loadFile = [this](int index, bool restoreCamera = false) -> bool
{
this->Internals->Engine->getInteractor().stopAnimation();

f3d::log::debug("========== Loading 3D file ==========");

if (restoreCamera)
{
f3d::camera& cam = this->Internals->Engine->getWindow().getCamera();
const auto camState = cam.getState();
this->LoadFile(index, true);
cam.setState(camState);
}
else
{
this->LoadFile(index, true);
}

f3d::log::debug("========== Rendering ==========");

this->Render();
return true;
};

if (keySym == "Left")
{
return loadFile(-1);
return this->LoadRelativeFile(-1);
}
if (keySym == "Right")
{
return loadFile(+1);
return this->LoadRelativeFile(+1);
}
if (keySym == "Up")
{
return loadFile(0, true);
return this->LoadRelativeFile(0, true);
}
if (keySym == "Down")
{
Expand All @@ -255,7 +264,7 @@ int F3DStarter::Start(int argc, char** argv)
this->Internals->FilesList[static_cast<size_t>(this->Internals->CurrentFileIndex)]
.parent_path(),
true);
return loadFile(0);
return this->LoadRelativeFile(0);
}
return true;
}
Expand All @@ -279,7 +288,7 @@ int F3DStarter::Start(int argc, char** argv)
this->Internals->Engine->getOptions().set("render.background.skybox", true);

// Rendering now is needed for correct lighting
this->Render();
this->Render(true);
}
else
{
Expand Down Expand Up @@ -442,6 +451,8 @@ int F3DStarter::Start(int argc, char** argv)
f3d::log::error("This is a headless build of F3D, interactive rendering is not supported");
return EXIT_FAILURE;
#else
// Create the event loop repeating timer
interactor.createTimerCallBack(30, [this]() { this->EventLoop(); });

Check warning on line 455 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L455

Added line #L455 was not covered by tests
this->Render();
interactor.start();
#endif
Expand All @@ -454,6 +465,7 @@ int F3DStarter::Start(int argc, char** argv)
//----------------------------------------------------------------------------
void F3DStarter::LoadFile(int index, bool relativeIndex)
{
f3d::log::debug("========== Loading 3D file ==========");
// When loading a file, store any changed options
// into the dynamic options and use these dynamic option as the default
// for loading the file while still applying file specific options on top of it
Expand Down Expand Up @@ -603,7 +615,19 @@ void F3DStarter::LoadFile(int index, bool relativeIndex)
}
}

if (!this->Internals->LoadedFile)
if (this->Internals->LoadedFile)
{
if (true) // TODO should be controlled with an option
{
if (this->Internals->FolderWatchId.id > 0)
{
dmon_unwatch(this->Internals->FolderWatchId);
}
this->Internals->FolderWatchId = dmon_watch(
filePath.parent_path().string().c_str(), &F3DInternals::dmonFolderChanged, 0, this);
}
}
else
{
// No file loaded, remove any previously loaded file
loader.loadGeometry("", true);
Expand All @@ -614,10 +638,19 @@ void F3DStarter::LoadFile(int index, bool relativeIndex)
}

//----------------------------------------------------------------------------
void F3DStarter::Render()
void F3DStarter::Render(bool force)
{
this->Internals->Engine->getWindow().render();
f3d::log::debug("Render done");
if (force)
{
f3d::log::debug("========== Rendering ==========");
this->Internals->Engine->getWindow().render();
f3d::log::debug("Render done");
}
else
{
// Render(true) will be called by the next event loop
this->Internals->SoftRender = true;
}
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -653,7 +686,9 @@ int F3DStarter::AddFile(const fs::path& path, bool quiet)

if (it == this->Internals->FilesList.end())
{
this->Internals->FilesListMutex.lock();
this->Internals->FilesList.push_back(tmpPath);
this->Internals->FilesListMutex.unlock();
return static_cast<int>(this->Internals->FilesList.size()) - 1;
}
else
Expand All @@ -666,3 +701,40 @@ int F3DStarter::AddFile(const fs::path& path, bool quiet)
}
}
}

//----------------------------------------------------------------------------
bool F3DStarter::LoadRelativeFile(int index, bool restoreCamera)
{
this->Internals->Engine->getInteractor().stopAnimation();

if (restoreCamera)
{
f3d::camera& cam = this->Internals->Engine->getWindow().getCamera();
const auto camState = cam.getState();
this->LoadFile(index, true);
cam.setState(camState);
}
else
{
this->LoadFile(index, true);
}

this->Render();

return true;
}

//----------------------------------------------------------------------------
void F3DStarter::EventLoop()

Check warning on line 728 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L728

Added line #L728 was not covered by tests
{
if (this->Internals->ReloadFile)

Check warning on line 730 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L730

Added line #L730 was not covered by tests
{
this->LoadRelativeFile(0, true);
this->Internals->ReloadFile = false;

Check warning on line 733 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L732-L733

Added lines #L732 - L733 were not covered by tests
}
if (this->Internals->SoftRender)

Check warning on line 735 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L735

Added line #L735 was not covered by tests
{
this->Render(true);
this->Internals->SoftRender = false;

Check warning on line 738 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L737-L738

Added lines #L737 - L738 were not covered by tests
}
}

Check warning on line 740 in application/F3DStarter.cxx

View check run for this annotation

Codecov / codecov/patch

application/F3DStarter.cxx#L740

Added line #L740 was not covered by tests
17 changes: 15 additions & 2 deletions application/F3DStarter.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class F3DStarter
void LoadFile(int index = 0, bool relativeIndex = false);

/**
* Trigger a render
* Trigger a render on the next event loop, use force to trigger it on call
*/
void Render();
void Render(bool force = false);

F3DStarter();
~F3DStarter();
Expand All @@ -47,6 +47,19 @@ class F3DStarter
private:
class F3DInternals;
std::unique_ptr<F3DInternals> Internals;

/**
* Internal method triggered when interacting with the application
* that load a file using relative index and handle camera restore
*/
bool LoadRelativeFile(int relativeIndex = 0, bool restoreCamera = false);

/**
* Internal event loop that is triggered repeatdly to handle specific events:
* - Render
* - ReloadFile
*/
void EventLoop();
};

#endif
Loading

0 comments on commit f73f8df

Please sign in to comment.