diff --git a/library/phx/input/device.cpp b/library/phx/input/device.cpp index 5c68859d70073a2d10a384ed647c75afdd66c9b0..fd9d038ce9eb4aa322fa8a8e5332c8f3b1936f19 100644 --- a/library/phx/input/device.cpp +++ b/library/phx/input/device.cpp @@ -20,6 +20,19 @@ // limitations under the License. //------------------------------------------------------------------------------ +#include <algorithm> + #include "phx/input/device.hpp" -namespace phx {} // namespace phx +namespace phx { + +void Device::EventDistributer::AddDevice(Device* device) { + devices_.push_back(device); +} +void Device::EventDistributer::RemoveDevice(Device* device) { + auto iterator = + std::remove_if(devices_.begin(), devices_.end(), + [device](Device* iteratee) { return device == iteratee; }); + devices_.erase(iterator, devices_.end()); +} +} // namespace phx diff --git a/library/phx/input/device.hpp b/library/phx/input/device.hpp index c477639764a905efdc712809d5a74034be7aaf98..995d210a3eaa2e825c1a14a30f4fbd12f96ff474 100644 --- a/library/phx/input/device.hpp +++ b/library/phx/input/device.hpp @@ -23,6 +23,8 @@ #ifndef LIBRARY_PHX_INPUT_DEVICE_HPP_ #define LIBRARY_PHX_INPUT_DEVICE_HPP_ +#include <vector> + #include "phx/export.hpp" namespace phx { @@ -31,6 +33,16 @@ class PHOENIX_EXPORT Device { public: virtual ~Device() = default; virtual void Update() = 0; + + class EventDistributer { + public: + virtual void Update() = 0; + void AddDevice(Device* device); + void RemoveDevice(Device* device); + + protected: + std::vector<Device*> devices_; + }; }; } // namespace phx diff --git a/library/phx/input/sdl_device.cpp b/library/phx/input/sdl_device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..298d6cdc9f3612721dbba816aae9e340b36c7fa9 --- /dev/null +++ b/library/phx/input/sdl_device.cpp @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#include "phx/input/sdl_device.hpp" + +#include "phx/core/logger.hpp" + +namespace phx { + +int SDLDevice::reference_counter_ = 0; +std::mutex SDLDevice::SDL_event_init_mutex_; +SDLDevice::SDLEventDistributer SDLDevice::SDL_event_distributer; + +SDLDevice::SDLDevice() { + SDL_event_init_mutex_.lock(); + if (reference_counter_ == 0) { + SDL_Init(SDL_INIT_EVENTS); + } + SDL_event_distributer.AddDevice(this); + reference_counter_++; + SDL_event_init_mutex_.unlock(); +} + +SDLDevice::~SDLDevice() { + SDL_event_init_mutex_.lock(); + reference_counter_--; + if (reference_counter_ == 0) { + SDL_QuitSubSystem(SDL_INIT_EVENTS); + } + SDL_event_distributer.RemoveDevice(this); + SDL_event_init_mutex_.unlock(); +} + +void SDLDevice::Update() { SDL_event_distributer.Update(); } + +void SDLDevice::SDLEventDistributer::Update() { + SDL_Event event; + while (SDL_PollEvent(&event) != 0) { + for (Device* device : devices_) { + dynamic_cast<SDLDevice*>(device)->OnSDLEvent(event); + } + } +} + +} // namespace phx diff --git a/library/phx/input/sdl_device.hpp b/library/phx/input/sdl_device.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30e1947ea84c6940bda6bd683bcc836e7652ea46 --- /dev/null +++ b/library/phx/input/sdl_device.hpp @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// Project Phoenix +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualization Group. +//------------------------------------------------------------------------------ +// License +// +// Licensed under the 3-Clause BSD License (the "License"); +// you may not use this file except in compliance with the License. +// See the file LICENSE for the full text. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//------------------------------------------------------------------------------ + +#ifndef LIBRARY_PHX_INPUT_SDL_DEVICE_HPP_ +#define LIBRARY_PHX_INPUT_SDL_DEVICE_HPP_ + +#include <mutex> +#include <vector> + +#include "phx/input/device.hpp" +#include "phx/suppress_warnings.hpp" + +SUPPRESS_WARNINGS_BEGIN +#include "SDL.h" +SUPPRESS_WARNINGS_END + +#include "phx/export.hpp" + +namespace phx { + +class PHOENIX_EXPORT SDLDevice : public Device { + public: + SDLDevice(); + virtual ~SDLDevice(); + + virtual void Update(); + + virtual void OnSDLEvent(const SDL_Event& event) = 0; + + protected: + class SDLEventDistributer : public EventDistributer { + public: + void Update() override; + }; + static SDLEventDistributer SDL_event_distributer; + + private: + static int reference_counter_; + static std::mutex SDL_event_init_mutex_; +}; + +} // namespace phx + +#endif // LIBRARY_PHX_INPUT_SDL_DEVICE_HPP_ diff --git a/library/phx/input/tracked_device.cpp b/library/phx/input/tracked_device.cpp index 0800a10dc0068f407972ce018bb7a60a2d17636a..05582a0dc7bde089eb12fc24f5b79779a2b5d4e3 100644 --- a/library/phx/input/tracked_device.cpp +++ b/library/phx/input/tracked_device.cpp @@ -94,23 +94,11 @@ bool TrackedDevice::IsActive() const { return id_ != vr::k_unTrackedDeviceIndexInvalid; } -void TrackedDevice::OpenVREventDistributer::AddDevice(TrackedDevice* device) { - tracked_devices_.push_back(device); -} - -void TrackedDevice::OpenVREventDistributer::RemoveDevice( - TrackedDevice* device) { - auto iterator = - std::remove_if(tracked_devices_.begin(), tracked_devices_.end(), - [device](Device* iteratee) { return device == iteratee; }); - tracked_devices_.erase(iterator, tracked_devices_.end()); -} - void TrackedDevice::OpenVREventDistributer::Update() { vr::VREvent_t event; while (vr::VRSystem()->PollNextEvent(&event, sizeof(event))) { - for (TrackedDevice* device : tracked_devices_) { - device->OnOpenVREvent(event); + for (Device* device : devices_) { + dynamic_cast<TrackedDevice*>(device)->OnOpenVREvent(event); } } } diff --git a/library/phx/input/tracked_device.hpp b/library/phx/input/tracked_device.hpp index d02805708c3326d5f9e6cbf24954f938b4e8c79f..a6ee0bb904daa675fb9a999b982c9c73b50b459e 100644 --- a/library/phx/input/tracked_device.hpp +++ b/library/phx/input/tracked_device.hpp @@ -54,18 +54,13 @@ class PHOENIX_EXPORT TrackedDevice : public Device { virtual void OnOpenVREvent(const vr::VREvent_t& event) = 0; protected: - class OpenVREventDistributer { + class OpenVREventDistributer : public EventDistributer { public: - void Update(); - void AddDevice(TrackedDevice* device); - void RemoveDevice(TrackedDevice* device); - - private: - std::vector<TrackedDevice*> tracked_devices_; + void Update() override; }; + static OpenVREventDistributer vr_event_distributer; static vr::IVRSystem* vr_system_; - static OpenVREventDistributer vr_event_distributer; static std::vector<vr::TrackedDevicePose_t> last_wait_get_poses_; glm::mat4 pose_; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f63ed905d8e76ba508e35cf4c75092d0c56031d9..7ad4f915c9263e626f06cab1b067a86e49645072 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -174,7 +174,9 @@ add_test_cpplint(NAME "phoenix-tests--cpplint" autoremove_mocked_test_source_from(${PHOENIX_TEST_SOURCES}) add_mocked_test(test_clear_pass LIBRARIES phoenix MOCKS opengl_mock) -add_mocked_test(test_input_system LIBRARIES phoenix MOCKS openvr_mock sdl_mock) +add_mocked_test(test_SDL_device LIBRARIES phoenix MOCKS sdl_mock) +add_mocked_test(test_mouse LIBRARIES phoenix MOCKS sdl_mock) +add_mocked_test(test_keyboard LIBRARIES phoenix MOCKS sdl_mock) add_mocked_test(test_geometry_pass LIBRARIES phoenix test_utilities MOCKS opengl_mock sdl_mock) add_mocked_test(test_rendering_system LIBRARIES phoenix MOCKS opengl_mock sdl_mock) add_mocked_test(test_shader LIBRARIES phoenix MOCKS opengl_mock) diff --git a/tests/src/test_input_system.cpp b/tests/src/test_SDL_device.cpp similarity index 68% rename from tests/src/test_input_system.cpp rename to tests/src/test_SDL_device.cpp index 7ac9cbc35cd66467dc29edadfd45c862b2613313..766f74b41bc99a005c29b7f8dfbaebd31c27b92d 100644 --- a/tests/src/test_input_system.cpp +++ b/tests/src/test_SDL_device.cpp @@ -25,15 +25,12 @@ #include "catch/catch.hpp" #include "phx/core/engine.hpp" -#include "phx/input/input_system.hpp" +#include "phx/input/sdl_device.hpp" #include "trompeloeil.hpp" #include "phx/suppress_warnings.hpp" -SUPPRESS_WARNINGS_BEGIN -#include "mocks/openvr_mock.hpp" -SUPPRESS_WARNINGS_END #include "mocks/sdl_mock.hpp" using trompeloeil::_; @@ -41,26 +38,30 @@ using trompeloeil::ne; extern template struct trompeloeil::reporter<trompeloeil::specialized>; +class SomeSDLDevice : public phx::SDLDevice { + MAKE_MOCK1(OnSDLEvent, void(const SDL_Event&)); +}; + SCENARIO("The input system captures low-level input events and forwards them.", - "[phx][phx::InputSystem]") { + "[phx][phx::SDLDevice]") { SDL_MOCK_ALLOW_ANY_CALL - OPENVR_MOCK_ALLOW_ANY_CALL - GIVEN("An engine with a DisplaySystem.") { - phx::Engine engine; - WHEN("I create an input system.") { - THEN("SDL event subsystem is initialized.") { - REQUIRE_CALL(sdl_mock.Get(), SDL_Init(SDL_INIT_EVENTS)).RETURN(0); - engine.CreateSystem<phx::InputSystem>(); - } - } + WHEN("I create an SDL device.") { + THEN("SDL event subsystem is initialized.") { + REQUIRE_CALL(sdl_mock.Get(), SDL_Init(SDL_INIT_EVENTS)).RETURN(0); + auto device = std::make_unique<SomeSDLDevice>(); - GIVEN("An input system.") { - phx::InputSystem* input_system = engine.CreateSystem<phx::InputSystem>(); - WHEN("The input system is updated.") { + WHEN("The SDL device is updated.") { THEN("SDL is requested to poll the pending events.") { - REQUIRE_CALL(sdl_mock.Get(), SDL_PollEvent(_)).RETURN(0); - input_system->Update(phx::FrameTimer::TimeInfo()); + REQUIRE_CALL(sdl_mock.Get(), SDL_PollEvent(_)).RETURN(false); + device->Update(); + + WHEN("The SDL device is destroyed.") { + THEN("SDL is requested to shutdown the event stuff.") { + REQUIRE_CALL(sdl_mock.Get(), SDL_QuitSubSystem(SDL_INIT_EVENTS)); + device.reset(); + } + } } } }