Skip to content

Commit

Permalink
add Exotic Inputs Service: injecting input device controls (e.g. game…
Browse files Browse the repository at this point in the history
…pads) into graph modules (e.g. View 3D)
  • Loading branch information
geringsj committed Sep 25, 2023
1 parent 477fd57 commit 71ae01b
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 0 deletions.
6 changes: 6 additions & 0 deletions frontend/main/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "CLIConfigParsing.h"
#include "CUDA_Service.hpp"
#include "Command_Service.hpp"
#include "ExoticInputs_Service.hpp"
#include "FrameStatistics_Service.hpp"
#include "FrontendServiceCollection.hpp"
#include "GUI_Service.hpp"
Expand Down Expand Up @@ -100,6 +101,10 @@ int main(const int argc, const char** argv) {
openglConfig.forceWindowSize = config.force_window_size;
gl_service.setPriority(2);

megamol::frontend::ExoticInputs_Service exoticinputs_service;
megamol::frontend::ExoticInputs_Service::Config exoticinputsConfig;
exoticinputs_service.setPriority(gl_service.getPriority() + 1); // depends on gamepad updates from GLFW

megamol::frontend::GUI_Service gui_service;
megamol::frontend::GUI_Service::Config guiConfig;
guiConfig.backend = (with_gl) ? (megamol::gui::GUIRenderBackend::OPEN_GL) : (megamol::gui::GUIRenderBackend::CPU);
Expand Down Expand Up @@ -196,6 +201,7 @@ int main(const int argc, const char** argv) {
if (with_gl) {
services.add(gl_service, &openglConfig);
}
services.add(exoticinputs_service, &exoticinputsConfig);
services.add(gui_service, &guiConfig);
services.add(lua_service_wrapper, &luaConfig);
services.add(screenshot_service, &screenshotConfig);
Expand Down
3 changes: 3 additions & 0 deletions frontend/services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ file(GLOB_RECURSE header_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"remote_service/*.hpp"
"profiling_service/*.hpp"
"vr_service/*.hpp"
"exotic_inputs/*.hpp"
# "service_template/*.hpp"
)

Expand All @@ -48,6 +49,7 @@ file(GLOB_RECURSE source_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"remote_service/*.cpp"
"profiling_service/*.cpp"
"vr_service/*.cpp"
"exotic_inputs/*.cpp"
# "service_template/*.cpp"
)

Expand Down Expand Up @@ -109,6 +111,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"gui/3rd"
"gui/src"
"vr_service"
"exotic_inputs"
# "service_template"
)

Expand Down
138 changes: 138 additions & 0 deletions frontend/services/exotic_inputs/ExoticInputs_Service.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* ExoticInputs_Service.cpp
*
* Copyright (C) 2022 by MegaMol Team
* Alle Rechte vorbehalten.
*/

#include "ExoticInputs_Service.hpp"

#include "GamepadState.h"

#include "GUIRegisterWindow.h" // register UI window for remote control
#include "imgui_stdlib.h"

// local logging wrapper for your convenience until central MegaMol logger established
#include "mmcore/utility/log/Log.h"

#include <algorithm>

static const std::string service_name = "ExoticInputs_Service: ";
static void log(std::string const& text) {
const std::string msg = service_name + text;
megamol::core::utility::log::Log::DefaultLog.WriteInfo(msg.c_str());
}

static void log_error(std::string const& text) {
const std::string msg = service_name + text;
megamol::core::utility::log::Log::DefaultLog.WriteError(msg.c_str());
}

static void log_warning(std::string const& text) {
const std::string msg = service_name + text;
megamol::core::utility::log::Log::DefaultLog.WriteWarn(msg.c_str());
}


namespace megamol {
namespace frontend {

ExoticInputs_Service::ExoticInputs_Service() {
// init members to default states
}

ExoticInputs_Service::~ExoticInputs_Service() {
// clean up raw pointers you allocated with new, which is bad practice and nobody does
}

bool ExoticInputs_Service::init(void* configPtr) {
if (configPtr == nullptr)
return false;

return init(*static_cast<Config*>(configPtr));
}

bool ExoticInputs_Service::init(const Config& config) {
// initialize your service and its provided resources using config parameters
// for now, you dont need to worry about your service beeing initialized or closed multiple times
// init() and close() only get called once in the lifetime of each service object
// but maybe more instances of your service will get created? this may be relevant for central resources you manage (like libraries, network connections).

m_providedResourceReferences = {};

m_requestedResourcesNames = {
"optional<Connected_Gamepads>",
"optional<GUIRegisterWindow>",
};

log("initialized successfully");
return true;
}

void ExoticInputs_Service::close() {}

std::vector<FrontendResource>& ExoticInputs_Service::getProvidedResources() {
return m_providedResourceReferences;
}

const std::vector<std::string> ExoticInputs_Service::getRequestedResourceNames() const {
return m_requestedResourcesNames;
}

void ExoticInputs_Service::setRequestedResources(std::vector<FrontendResource> resources) {
m_requestedResourceReferences = resources;

gamepad_window();
}

void ExoticInputs_Service::updateProvidedResources() {}

void ExoticInputs_Service::digestChangedRequestedResources() {}

void ExoticInputs_Service::resetProvidedResources() {}

void ExoticInputs_Service::preGraphRender() {}

void ExoticInputs_Service::postGraphRender() {}

void ExoticInputs_Service::gamepad_window() const {
auto maybe_gamepad_resource =
m_requestedResourceReferences[0].getOptionalResource<megamol::frontend_resources::Connected_Gamepads>();
auto maybe_window_resource =
m_requestedResourceReferences[1].getOptionalResource<megamol::frontend_resources::GUIRegisterWindow>();

if (maybe_gamepad_resource.has_value() && maybe_window_resource.has_value()) {
// draw window showing gamepad stats
auto& gui_window = maybe_window_resource.value().get();
auto& connected_gamepads = maybe_gamepad_resource.value().get();

gui_window.register_window("GLFW Gamepads ", [&](megamol::gui::AbstractWindow::BasicConfig& window_config) {
for (auto& gamepad : connected_gamepads.gamepads) {
window_config.flags = ImGuiWindowFlags_AlwaysAutoResize;

ImGui::Text(gamepad.get().name.c_str());

int i = 0;
for (auto axis : gamepad.get().axes) {
ImGui::Text(("Axis " + std::to_string(i) + ": " + std::to_string(axis)).c_str());
ImGui::SameLine();
i++;
}
ImGui::NewLine();

i = 0;
for (auto button : gamepad.get().buttons) {
ImGui::Text(("Button " + std::to_string(i) + ": " + std::to_string(button)).c_str());
ImGui::SameLine();
i++;
}
ImGui::NewLine();
ImGui::Separator();
}
});
}
}


} // namespace frontend
} // namespace megamol
59 changes: 59 additions & 0 deletions frontend/services/exotic_inputs/ExoticInputs_Service.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* ExoticInputs_Service.hpp
*
* Copyright (C) 2022 by MegaMol Team
* Alle Rechte vorbehalten.
*/

#pragma once

#include "AbstractFrontendService.hpp"

namespace megamol {
namespace frontend {

// The Exotic Inputs Service is supposed to implement the injection of raw input device state (e.g.gamepads via GLFW)
// into the MegaMol Graph by matching input devices to graph modules which can be controlled in some usefull way using that device
// So this ervice looks up present input device resources, or manages input devices on his own, and knows how to connect them to graph modules
// For example, gamepads may be used to control View3D Cameras or positions of Clipping Planes in space
class ExoticInputs_Service final : public AbstractFrontendService {
public:
struct Config {};

std::string serviceName() const override {
return "ExoticInputs_Service";
}

ExoticInputs_Service();
~ExoticInputs_Service();

bool init(const Config& config);
bool init(void* configPtr) override;
void close() override;

std::vector<FrontendResource>& getProvidedResources() override;
const std::vector<std::string> getRequestedResourceNames() const override;
void setRequestedResources(std::vector<FrontendResource> resources) override;

void updateProvidedResources() override;
void digestChangedRequestedResources() override;
void resetProvidedResources() override;
void preGraphRender() override;
void postGraphRender() override;

// from AbstractFrontendService
// int setPriority(const int p) // priority initially 0
// int getPriority() const;
// bool shouldShutdown() const; // shutdown initially false
// void setShutdown(const bool s = true);

private:
std::vector<FrontendResource> m_providedResourceReferences;
std::vector<std::string> m_requestedResourcesNames;
std::vector<FrontendResource> m_requestedResourceReferences;

void gamepad_window() const;
};

} // namespace frontend
} // namespace megamol

0 comments on commit 71ae01b

Please sign in to comment.