Skip to content

Commit

Permalink
Introduce a new interaction API
Browse files Browse the repository at this point in the history
  • Loading branch information
mwestphal committed Nov 12, 2023
1 parent e272618 commit cbc9b58
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 10 deletions.
1 change: 1 addition & 0 deletions application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ int F3DStarter::Start(int argc, char** argv)

f3d::window& window = this->Internals->Engine->getWindow();
f3d::interactor& interactor = this->Internals->Engine->getInteractor();
interactor.addDefaultKeyPressInteractions(); // TODO where should we put this ?
interactor.setKeyPressCallBack(
[this](int, const std::string& keySym) -> bool
{
Expand Down
3 changes: 3 additions & 0 deletions library/private/interactor_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class interactor_impl : public interactor
interactor_impl(options& options, window_impl& window, loader_impl& loader);
~interactor_impl() override;

interactor& addKeyPressCallBack(const std::string& keySym, ModifierKeys modifiers, std::function<void()> callBack) override;
interactor& addKeyPressToggle(const std::string& keySym, ModifierKeys modifiers, const std::string& option) override;

interactor& setKeyPressCallBack(std::function<bool(int, std::string)> callBack) override;
interactor& setDropFilesCallBack(std::function<bool(std::vector<std::string>)> callBack) override;

Expand Down
35 changes: 35 additions & 0 deletions library/public/interactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,41 @@ namespace f3d
class F3D_EXPORT interactor
{
public:

/**
* Enumeration of supported modifier combination, in binary.
*/
enum class ModifierKeys : unsigned char
{
ANY = 0x80, // 10000000
NONE = 0x0, // 00000000
CTRL = 0x1, // 00000001
SHIFT = 0x2, // 00000010
CTRL_SHIFT = 0x3 // 00000011
};

/**
* Use this method to specify your own keypress callback for a specified keysym and modifiers flag.
* keysym being the pressed key symbol, TODO list ?
* modifiers is a binary flag from the dedicated enum.
* Adding a callback for same keySym and modifiers as any existing key press interaction will remove the previous one.
* Expected API:
* \code
* void callBack()
* \endcode
*/
virtual interactor& addKeyPressCallBack(const std::string& keySym, ModifierKeys modifiers, std::function<void()> callBack) = 0;

/**
* Use this method to specify your to toggle a boolean option for a specified keysym and modifiers flag.
* keysym being the pressed key symbol, TODO list ?
* modifiers is a binary flag from the dedicated enum.
* Adding a toggle for same keySym and modifiers as any existing key press interaction will remove the previous one.
*/
virtual interactor& addKeyPressToggle(const std::string& keySym, ModifierKeys modifiers, const std::string& option) = 0;

virtual interactor& addDefaultKeyPressInteractions();

/**
* Use this method to specify your own keypress callback, with the expected API:
* \code
Expand Down
28 changes: 28 additions & 0 deletions library/src/interactor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@

namespace f3d
{

//----------------------------------------------------------------------------
interactor& interactor::addDefaultKeyPressInteractions()
{
this->addKeyPressToggle("b", ModifierKeys::ANY, "ui.bar");
this->addKeyPressToggle("p", ModifierKeys::ANY, "render.effect.translucency-support");
this->addKeyPressToggle("q", ModifierKeys::ANY, "render.effect.ambient-occlusion");
this->addKeyPressToggle("a", ModifierKeys::ANY, "render.effect.anti-aliasing");
this->addKeyPressToggle("t", ModifierKeys::ANY, "render.effect.tone-mapping");
this->addKeyPressToggle("e", ModifierKeys::ANY, "render.show-edges");
this->addKeyPressToggle("x", ModifierKeys::ANY, "interactor.axis");
this->addKeyPressToggle("g", ModifierKeys::ANY, "render.grid.enable");
this->addKeyPressToggle("n", ModifierKeys::ANY, "ui.filename");
this->addKeyPressToggle("m", ModifierKeys::ANY, "ui.metadata");
this->addKeyPressToggle("r", ModifierKeys::ANY, "render.raytracing.enable");
this->addKeyPressToggle("d", ModifierKeys::ANY, "render.raytracing.denoise");
this->addKeyPressToggle("v", ModifierKeys::ANY, "model.volume.enable");
this->addKeyPressToggle("i", ModifierKeys::ANY, "model.volume.inverse");
this->addKeyPressToggle("o", ModifierKeys::ANY, "model.point-sprites.enable");
this->addKeyPressToggle("u", ModifierKeys::ANY, "render.background.blur");
this->addKeyPressToggle("k", ModifierKeys::ANY, "interactor.trackball");
this->addKeyPressToggle("f", ModifierKeys::ANY, "render.hdri.ambient");
this->addKeyPressToggle("f", ModifierKeys::ANY, "render.background.skybox");
this->addKeyPressToggle("h", ModifierKeys::ANY, "ui.cheatsheet");
return *this;
}

//----------------------------------------------------------------------------
const std::vector<std::pair<std::string, std::string> >& interactor::getDefaultInteractionsInfo()
{
// clang-format off
Expand Down
83 changes: 73 additions & 10 deletions library/src/interactor_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,58 @@ class interactor_impl::internals

internals* self = static_cast<internals*>(clientData);
vtkRenderWindowInteractor* rwi = self->Style->GetInteractor();
int keyCode = std::toupper(rwi->GetKeyCode());
std::string keySym = rwi->GetKeySym();
if (keySym.length() > 0)
int shift = rwi->GetShiftKey();
int ctrl = rwi->GetControlKey();

// Retrocompatible support of the KeyPressUserCallBack
int keyCode = std::toupper(rwi->GetKeyCode());
std::string upKeySym = keySym;
if (upKeySym.length() > 0)
{
// Make sure key symbols starts with an upper char (e.g. "space")
keySym[0] = std::toupper(keySym[0]);
upKeySym[0] = std::toupper(upKeySym[0]);
}

if (self->KeyPressUserCallBack(keyCode, keySym))
if (self->KeyPressUserCallBack(keyCode, upKeySym))
{
return;
}

// Actual key press implementation
// Check of an *any modifier* interaction first
auto mapKey = std::make_pair(keySym, ModifierKeys::ANY);
auto callBack = self->KeyCallBacks.find(mapKey);
if (callBack != self->KeyCallBacks.end())
{
callBack->second();
}
else
{
// Check for an interaction callBack with modifiers
ModifierKeys modifiers = ModifierKeys::NONE;
if (shift == 1 && ctrl == 1)
{
modifiers = ModifierKeys::CTRL_SHIFT;
}
else if (ctrl == 1)
{
modifiers = ModifierKeys::CTRL;
}
else if (shift == 1)
{
modifiers = ModifierKeys::SHIFT;
}
mapKey.second = modifiers;

callBack = self->KeyCallBacks.find(mapKey);
if (callBack != self->KeyCallBacks.end())
{
callBack->second();
}
}

// TODO remove old code below
// No user defined behavior, use standard behavior
vtkRenderWindow* renWin = self->Window.GetRenderWindow();
vtkF3DRenderer* ren = vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer());
Expand Down Expand Up @@ -197,6 +236,7 @@ class interactor_impl::internals
render = true;
}
break;
/*
case 'B':
self->Options.toggle("ui.bar");
render = true;
Expand Down Expand Up @@ -237,13 +277,15 @@ class interactor_impl::internals
self->Options.toggle("ui.metadata");
render = true;
break;
*/
case 'Z':
self->Options.toggle("ui.fps");
self->Window.render();
self->Window.render();
// XXX: Double render is needed here
break;
case 'R':
/*
case 'R':
self->Options.toggle("render.raytracing.enable");
render = true;
break;
Expand Down Expand Up @@ -279,6 +321,7 @@ class interactor_impl::internals
self->Options.toggle("render.background.skybox");
render = true;
break;
*/
case 'L':
{
const double intensity = self->Options.getAsDouble("render.light.intensity");
Expand All @@ -303,10 +346,10 @@ class interactor_impl::internals
render = true;
break;
}
case 'H':
/* case 'H':
self->Options.toggle("ui.cheatsheet");
render = true;
break;
break;*/
case '?':
self->Window.PrintColoringDescription(log::VerboseLevel::INFO);
self->Window.PrintSceneDescription(log::VerboseLevel::INFO);
Expand All @@ -328,16 +371,16 @@ class interactor_impl::internals
render = true;
break;
default:
if (keySym == F3D_EXIT_HOTKEY_SYM)
if (upKeySym == F3D_EXIT_HOTKEY_SYM)
{
self->StopInteractor();
}
else if (keySym == "Return")
else if (upKeySym == "Return")
{
self->Window.getCamera().resetToDefault();
render = true;
}
else if (keySym == "Space")
else if (upKeySym == "Space")
{
assert(self->AnimationManager);
self->AnimationManager->ToggleAnimation();
Expand Down Expand Up @@ -541,6 +584,7 @@ class interactor_impl::internals
vtkNew<vtkF3DInteractorStyle> Style;
vtkSmartPointer<vtkF3DInteractorEventRecorder> Recorder;
std::map<unsigned long, std::pair<int, std::function<void()> > > TimerCallBacks;
std::map<std::pair<std::string, ModifierKeys>, std::function<void()> > KeyCallBacks;

vtkNew<vtkCellPicker> CellPicker;
vtkNew<vtkPointPicker> PointPicker;
Expand All @@ -562,6 +606,25 @@ interactor_impl::interactor_impl(options& options, window_impl& window, loader_i
//----------------------------------------------------------------------------
interactor_impl::~interactor_impl() = default;

//----------------------------------------------------------------------------
interactor& interactor_impl::addKeyPressCallBack(const std::string& keySym, ModifierKeys modifiers, std::function<void()> callBack)
{
this->Internals->KeyCallBacks[std::make_pair(keySym, modifiers)] = callBack;
return *this;
}

//----------------------------------------------------------------------------
interactor& interactor_impl::addKeyPressToggle(const std::string& keySym, ModifierKeys modifiers, const std::string& option)
{
this->addKeyPressCallBack(keySym, modifiers,
[this, option]() -> void
{
this->Internals->Options.toggle(option);
this->Internals->Window.render();
});
return *this;
}

//----------------------------------------------------------------------------
interactor& interactor_impl::setKeyPressCallBack(std::function<bool(int, std::string)> callBack)
{
Expand Down

0 comments on commit cbc9b58

Please sign in to comment.