diff --git a/demos/viewer/src/viewer.cpp b/demos/viewer/src/viewer.cpp
index a5e5dc0390d4c6069bb079a3e661ad919d859a9b..bb293a384a638272b18eca2dd3b178a20fd135c8 100644
--- a/demos/viewer/src/viewer.cpp
+++ b/demos/viewer/src/viewer.cpp
@@ -52,57 +52,11 @@
#include "phx/transform.hpp"
#include "phx/window.hpp"
-#include "controller_behavior.hpp"
#include "navigation_behavior.hpp"
#include "phx/display_system_openvr.hpp"
#include "rotation_behavior.hpp"
#include "viewer_system.hpp"
-void AddControllerEntity(const std::shared_ptr<phx::Scene>& scene,
- phx::ResourcePointer<phx::Mesh> mesh,
- phx::ResourcePointer<phx::Material> material,
- ControllerBehavior::Side side) {
- phx::Entity* controller = scene->CreateEntity();
- controller->AddComponent<phx::MeshHandle>()->SetMesh(mesh);
- controller->AddComponent<phx::Transform>();
- controller->AddComponent<phx::MaterialHandle>()->SetMaterial(material);
- controller->AddComponent<ControllerBehavior>()->SetSide(side);
-}
-
-void AddController(const std::shared_ptr<phx::Scene>& scene,
- ControllerBehavior::Side side) {
- auto& resource_manager = phx::ResourceManager::instance();
-
- phx::ResourceDeclaration mesh_declaration{
- {"TYPE", "openVR"},
- {"OpenVR_type", "mesh"},
- {"side", (side == ControllerBehavior::RIGHT ? "right" : "left")}};
- auto mesh_proxy =
- phx::ResourceManager::instance().DeclareResource(mesh_declaration);
- mesh_proxy->Load();
-
- phx::ResourceDeclaration material_declaration{{"TYPE", "openVR"},
- {"OpenVR_type", "material"}};
- auto material_proxy = resource_manager.DeclareResource(material_declaration);
- material_proxy->Load();
-
- if (mesh_proxy->GetAs<phx::Mesh>() != nullptr) {
- AddControllerEntity(scene, phx::ResourcePointer<phx::Mesh>(mesh_proxy),
- phx::ResourcePointer<phx::Material>(material_proxy),
- side);
- }
-}
-
-void SetupOpenVRController(const std::shared_ptr<phx::Scene>& scene,
- phx::HMD* hmd) {
- auto& resource_manager = phx::ResourceManager::instance();
- auto openvr_loader = std::make_unique<phx::OpenVRResourceLoader>(hmd);
- resource_manager.RegisterResourceType("openVR", std::move(openvr_loader));
-
- AddController(scene, ControllerBehavior::RIGHT);
- AddController(scene, ControllerBehavior::LEFT);
-}
-
int main(int, char**) {
std::unique_ptr<phx::Engine> engine = phx::Setup::CreateDefaultEngine();
auto scene = engine->GetScene();
@@ -126,15 +80,8 @@ int main(int, char**) {
viewer_system->SetShowFramerate(!viewer_system->GetShowFramerate());
});
- auto display_system_hmd = engine->GetSystem<phx::DisplaySystemOpenVR>();
- if (display_system_hmd != nullptr) {
- auto hmd = display_system_hmd->GetHMD();
- if (hmd != nullptr) {
- // SetupOpenVRController(scene, hmd);
- }
- }
-
- phx::SceneLoader::InsertModelIntoScene("models/bunny.obj", scene.get());
+ phx::SceneLoader::InsertModelIntoScene(
+ "models/UniversityScene/Univers20171013.obj", scene.get());
std::vector<glm::quat> light_dirs{
glm::quat(glm::angleAxis(-0.25f * glm::pi<float>(), glm::vec3(1, 0, 0))),
diff --git a/library/phx/hmd.cpp b/library/phx/hmd.cpp
index a4cbcbbda4bfa35d6c9973ebdd0133e3760242a7..4f8c5d3e7edd18133fe39a504e9924a9548f1e20 100644
--- a/library/phx/hmd.cpp
+++ b/library/phx/hmd.cpp
@@ -80,6 +80,11 @@ std::vector<vr::TrackedDeviceIndex_t> HMD::GetControllerIndices() {
return std::move(indices);
}
+vr::ETrackedControllerRole HMD::GetControllerRoleForTrackedDeviceIndex(
+ vr::TrackedDeviceIndex_t device_index) const {
+ return vr_system_->GetControllerRoleForTrackedDeviceIndex(device_index);
+}
+
const glm::uvec2& HMD::GetViewportSize() const { return viewport_size_; }
const glm::mat4& HMD::GetProjectionMatrix(Side side) const {
@@ -137,7 +142,9 @@ glm::mat4 HMD::GetRightControllerTransformation() {
std::unique_ptr<phx::Mesh> HMD::GetControllerMesh(Controller controller) {
auto model = GetControllerModel(controller);
- if (model == nullptr) return nullptr;
+ if (model == nullptr) {
+ return nullptr;
+ }
auto mesh = std::make_unique<phx::Mesh>();
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;
@@ -177,7 +184,7 @@ vr::RenderModel_t* HMD::GetControllerModel(Controller controller) {
}
}
- vr::RenderModel_t* model;
+ vr::RenderModel_t* model = nullptr;
while (vr::VRRenderModels()->LoadRenderModel_Async(
&rendermodel_name[0], &model) == vr::VRRenderModelError_Loading) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -225,9 +232,9 @@ std::unique_ptr<Image> HMD::GetControllerTexture(int id) {
texture_map->rubTextureMapData + image_data.size(),
image_data.begin());
auto image = std::make_unique<phx::Image>(
- image_data, std::array<std::size_t, 2>{
+ &image_data[0], std::array<std::size_t, 2>{
{static_cast<std::size_t>(texture_map->unWidth),
- static_cast<std::size_t>(texture_map->unHeight)}});
+ static_cast<std::size_t>(texture_map->unHeight)}}, 32);
return image;
}
diff --git a/library/phx/hmd.hpp b/library/phx/hmd.hpp
index a3e0b7cfb165fc91f4e9622a6261cf803889fd59..82bedf2cfaf9e305a32b7126ec7415fd6635d45b 100644
--- a/library/phx/hmd.hpp
+++ b/library/phx/hmd.hpp
@@ -78,6 +78,8 @@ class PHOENIX_EXPORT HMD {
void Submit(Side side, gl::texture_2d* texture);
std::vector<vr::TrackedDeviceIndex_t> GetControllerIndices();
+ vr::ETrackedControllerRole GetControllerRoleForTrackedDeviceIndex(
+ vr::TrackedDeviceIndex_t device_index) const;
private:
glm::mat4 GetTransformationForRole(vr::ETrackedControllerRole role);
diff --git a/library/phx/image.hpp b/library/phx/image.hpp
index 5f686d332ed717a515565219c031645531368082..b9ccc8bcf7a0cb9f6cec1b2c406a9a6f15f1f941 100644
--- a/library/phx/image.hpp
+++ b/library/phx/image.hpp
@@ -71,7 +71,8 @@ class PHOENIX_EXPORT Image : public Resource, public Loggable {
static_cast<std::int32_t>(dimensions[1]),
static_cast<std::int32_t>((bits_per_pixel * dimensions[0] + 31) / 32 *
4),
- static_cast<std::int32_t>(bits_per_pixel), 0, 0, 0, false);
+ static_cast<std::int32_t>(bits_per_pixel), FI_RGBA_RED_MASK,
+ FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, false);
if (!native_) {
throw std::runtime_error("FreeImage_ConvertFromRawBitsEx failed.");
}
diff --git a/demos/viewer/src/controller_behavior.cpp b/library/phx/openvr_controller_behavior.cpp
similarity index 84%
rename from demos/viewer/src/controller_behavior.cpp
rename to library/phx/openvr_controller_behavior.cpp
index f4fc9a45a6bcdc867ff836d6a039a9039a924f09..51620fe1f74a172e3890a0207fa47f23c91a4383 100644
--- a/demos/viewer/src/controller_behavior.cpp
+++ b/library/phx/openvr_controller_behavior.cpp
@@ -20,14 +20,15 @@
// limitations under the License.
//------------------------------------------------------------------------------
-#include "controller_behavior.hpp"
+#include "openvr_controller_behavior.hpp"
#include "phx/entity.hpp"
#include "phx/runtime_component.hpp"
#include "phx/scene.hpp"
#include "phx/transform.hpp"
-void ControllerBehavior::OnUpdate() {
+namespace phx {
+void OpenVRControllerBehavior::OnUpdate() {
phx::Scene* scene = GetEntity()->GetScene();
phx::Entity* runtime_entity = nullptr;
if (side_ == Side::LEFT) {
@@ -48,8 +49,14 @@ void ControllerBehavior::OnUpdate() {
!(GetEntity()->GetFirstComponent<phx::Transform>()->GetParent() ==
runtime_entity->GetFirstComponent<phx::Transform>())) {
GetEntity()->GetFirstComponent<phx::Transform>()->SetParent(
- runtime_entity->GetFirstComponent<phx::Transform>());
+ runtime_entity->GetFirstComponent<phx::Transform>(), false);
}
}
-void ControllerBehavior::SetSide(Side side) { side_ = side; }
+void OpenVRControllerBehavior::SetSide(Side side) { side_ = side; }
+
+OpenVRControllerBehavior::Side OpenVRControllerBehavior::GetSide() const {
+ return side_;
+}
+
+} // namespace phx
diff --git a/demos/viewer/src/controller_behavior.hpp b/library/phx/openvr_controller_behavior.hpp
similarity index 79%
rename from demos/viewer/src/controller_behavior.hpp
rename to library/phx/openvr_controller_behavior.hpp
index 5f6855c2736df123f19220e24df2f6ccbd571a1a..c8fb9898d17f86bb238273837acb31dcc97df088 100644
--- a/demos/viewer/src/controller_behavior.hpp
+++ b/library/phx/openvr_controller_behavior.hpp
@@ -20,21 +20,26 @@
// limitations under the License.
//------------------------------------------------------------------------------
-#ifndef DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
-#define DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
+#ifndef LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
+#define LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
#include "phx/behavior.hpp"
+#include "phx/export.hpp"
-class ControllerBehavior : public phx::Behavior {
+namespace phx {
+
+class PHOENIX_EXPORT OpenVRControllerBehavior : public Behavior {
public:
enum Side { LEFT, RIGHT };
void OnUpdate() override;
void SetSide(Side side);
+ Side GetSide() const;
private:
Side side_ = Side::LEFT;
};
+} // namespace phx
-#endif // DEMOS_VIEWER_SRC_CONTROLLER_BEHAVIOR_HPP_
+#endif // LIBRARY_PHX_OPENVR_CONTROLLER_BEHAVIOR_HPP_
diff --git a/library/phx/openvr_controller_system.cpp b/library/phx/openvr_controller_system.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..737f3be65a0201f4929455f29bf46e43456cccc9
--- /dev/null
+++ b/library/phx/openvr_controller_system.cpp
@@ -0,0 +1,146 @@
+//------------------------------------------------------------------------------
+// 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 "openvr_controller_system.hpp"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "display_system_openvr.hpp"
+#include "logger.hpp"
+#include "material_handle.hpp"
+#include "mesh_handle.hpp"
+#include "openvr_controller_behavior.hpp"
+#include "openvr_resource_loader.hpp"
+#include "resource_manager.hpp"
+#include "resource_pointer.hpp"
+#include "transform.hpp"
+
+namespace phx {
+
+OpenVRControllerSystem::OpenVRControllerSystem(Engine* engine,
+ DisplaySystem* display_system)
+ : System(engine) {
+ // find HMD
+ hmd_ = dynamic_cast<DisplaySystemOpenVR*>(display_system)->GetHMD();
+ if (hmd_ == nullptr) {
+ error("Cannot use OpenVRControllerSystem without an HMD!");
+ return;
+ }
+
+ auto& resource_manager = ResourceManager::instance();
+ auto openvr_loader = std::make_unique<OpenVRResourceLoader>(hmd_);
+ resource_manager.RegisterResourceType("openVR", std::move(openvr_loader));
+}
+
+Entity* AddControllerEntity(const std::shared_ptr<phx::Scene>& scene,
+ ResourcePointer<Mesh> mesh,
+ ResourcePointer<Material> material,
+ OpenVRControllerBehavior::Side side) {
+ Entity* controller = scene->CreateEntity();
+ controller->AddComponent<MeshHandle>()->SetMesh(mesh);
+ controller->AddComponent<Transform>();
+ controller->AddComponent<MaterialHandle>()->SetMaterial(material);
+ controller->AddComponent<OpenVRControllerBehavior>()->SetSide(side);
+
+ return controller;
+}
+
+Entity* AddController(const std::shared_ptr<phx::Scene>& scene,
+ OpenVRControllerBehavior::Side side) {
+ auto& resource_manager = ResourceManager::instance();
+ std::string side_string =
+ side == OpenVRControllerBehavior::LEFT ? "left" : "right";
+
+ ResourceDeclaration mesh_declaration{
+ {"TYPE", "openVR"}, {"OpenVR_type", "mesh"}, {"side", side_string}};
+ auto mesh_proxy =
+ ResourceManager::instance().DeclareResource(mesh_declaration);
+ mesh_proxy->Load();
+
+ ResourceDeclaration material_declaration{
+ {"TYPE", "openVR"}, {"OpenVR_type", "material"}, {"side", side_string}};
+ auto material_proxy = resource_manager.DeclareResource(material_declaration);
+ material_proxy->Load();
+
+ if (mesh_proxy->GetAs<Mesh>() != nullptr) {
+ return AddControllerEntity(scene, ResourcePointer<Mesh>(mesh_proxy),
+ ResourcePointer<Material>(material_proxy), side);
+ }
+ return nullptr;
+}
+
+void OpenVRControllerSystem::Update(const FrameTimer::TimeInfo&) {
+ // check which controllers are active and update their scene representation,
+ // if necessary
+ if (!hmd_) return;
+ auto scene = GetEngine()->GetScene();
+ if (scene == nullptr) return;
+
+ // get controller entities in the scene
+ Entity* left_controller_entity = nullptr;
+ Entity* right_controller_entity = nullptr;
+ auto controller_entities =
+ GetEngine()->GetEntitiesWithComponents<OpenVRControllerBehavior>();
+ for (auto entity : controller_entities) {
+ if (entity->GetFirstComponent<OpenVRControllerBehavior>()->GetSide() ==
+ OpenVRControllerBehavior::LEFT) {
+ left_controller_entity = entity;
+ } else {
+ right_controller_entity = entity;
+ }
+ }
+
+ auto controller_indices = hmd_->GetControllerIndices();
+ bool left_controller_active = false;
+ bool right_controller_active = false;
+ for (auto idx : controller_indices) {
+ // is it a left controller?
+ auto role = hmd_->GetControllerRoleForTrackedDeviceIndex(idx);
+ if (role == vr::TrackedControllerRole_LeftHand) {
+ // do we have a left controller in the scene?
+ if (left_controller_entity == nullptr) {
+ // create that controller
+ left_controller_entity =
+ AddController(scene, OpenVRControllerBehavior::LEFT);
+ }
+ left_controller_active = true;
+ } else if (role == vr::TrackedControllerRole_RightHand) {
+ if (right_controller_entity == nullptr) {
+ right_controller_entity =
+ AddController(scene, OpenVRControllerBehavior::RIGHT);
+ }
+ right_controller_active = true;
+ }
+ }
+
+ // remove unnecessary entities
+ if (!left_controller_active && left_controller_entity != nullptr) {
+ scene->RemoveEntity(left_controller_entity);
+ }
+ if (!right_controller_active && right_controller_entity != nullptr) {
+ scene->RemoveEntity(right_controller_entity);
+ }
+}
+
+} // namespace phx
diff --git a/library/phx/openvr_controller_system.hpp b/library/phx/openvr_controller_system.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..21a3f8b91e243cd6643f34ed9921a31980561ed2
--- /dev/null
+++ b/library/phx/openvr_controller_system.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_OPENVR_CONTROLLER_SYSTEM_HPP_
+#define LIBRARY_PHX_OPENVR_CONTROLLER_SYSTEM_HPP_
+
+#include <memory>
+#include <vector>
+
+SUPPRESS_WARNINGS_BEGIN
+#include "glm/glm.hpp"
+SUPPRESS_WARNINGS_END
+
+#include "phx/display_system.hpp"
+#include "phx/engine.hpp"
+#include "phx/export.hpp"
+#include "phx/hmd.hpp"
+#include "phx/system.hpp"
+
+namespace phx {
+class PHOENIX_EXPORT OpenVRControllerSystem : public System {
+ public:
+ OpenVRControllerSystem() = delete;
+ OpenVRControllerSystem(const OpenVRControllerSystem&) = delete;
+ OpenVRControllerSystem(OpenVRControllerSystem&&) = default;
+ virtual ~OpenVRControllerSystem() = default;
+
+ OpenVRControllerSystem& operator=(const OpenVRControllerSystem&) = delete;
+ OpenVRControllerSystem& operator=(OpenVRControllerSystem&&) = default;
+
+ void Update(const FrameTimer::TimeInfo&) override;
+
+ protected:
+ template <typename SystemType, typename... SystemArguments>
+ friend SystemType* Engine::CreateSystem(SystemArguments&&... arguments);
+ OpenVRControllerSystem(Engine* engine, DisplaySystem* display_system);
+
+ private:
+ HMD* hmd_ = nullptr;
+};
+
+} // namespace phx
+
+#endif // LIBRARY_PHX_OPENVR_CONTROLLER_SYSTEM_HPP_
diff --git a/library/phx/setup.cpp b/library/phx/setup.cpp
index 05b837d3ae794d2c0ea33a6134acbaf19e8daaae..2b97bad44ba18b34ec81f4a458f3869c44af6318 100644
--- a/library/phx/setup.cpp
+++ b/library/phx/setup.cpp
@@ -35,6 +35,7 @@
#include "hmd.hpp"
#include "input_system.hpp"
#include "logger.hpp"
+#include "openvr_controller_system.hpp"
#include "render_target.hpp"
#include "rendering_system.hpp"
#include "tracking_system_openvr.hpp"
@@ -84,8 +85,11 @@ std::unique_ptr<Engine> Setup::CreateDefaultEngine() {
SetupDefaultFrameGraphOpenVR(rendering_system);
auto tracking_system =
engine->CreateSystem<TrackingSystemOpenVR>(displaysys_hmd);
+ auto controller_system = engine->CreateSystem<OpenVRControllerSystem>(
+ engine->GetSystem<DisplaySystem>());
engine->GetUpdateOrder().MoveBefore(tracking_system, rendering_system);
engine->GetUpdateOrder().MoveAfter(behavior_system, tracking_system);
+ engine->GetUpdateOrder().MoveAfter(tracking_system, controller_system);
} else {
auto render_targets = displaysys_window->CreateRenderTargets();
rendering_system->SetRenderTargets(&render_targets);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 0c516001fb8a2bb48d0353a54fac5d8469af3628..14e3a3d43d80b7ada144e5e8a3f81e07489abb90 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -226,6 +226,7 @@ add_mocked_test(test_shader MOCK_GLEW)
add_mocked_test(test_display_system MOCK_SDL)
add_mocked_test(test_engine MOCK_SDL MOCK_OPENVR MOCK_GLEW)
add_mocked_test(test_tracking_system MOCK_SDL MOCK_OPENVR)
+add_mocked_test(test_openvr_controller_system MOCK_SDL MOCK_OPENVR MOCK_GLEW)
add_mocked_test(integration_test_model_rendering MOCK_OPENVR)
add_mocked_test(integration_test_opengl_buffer_data_download MOCK_OPENVR)
diff --git a/tests/src/mocks/openvr_mock.hpp b/tests/src/mocks/openvr_mock.hpp
index 89ecec4ee202166ee92d3cf35ac315b825a7f496..77881d7054b6d4a82e1777140ec2b34724e70a8c 100644
--- a/tests/src/mocks/openvr_mock.hpp
+++ b/tests/src/mocks/openvr_mock.hpp
@@ -39,11 +39,11 @@ using trompeloeil::_;
class OPENVR_MOCK_EXPORT OpenVRMockInternal {
public:
MAKE_MOCK0(VR_IsHmdPresent, bool());
- MAKE_MOCK2(VR_GetGenericInterface, void*(const char*, vr::EVRInitError*));
- MAKE_MOCK3(VR_InitInternal2,
- uint32_t(vr::EVRInitError*, vr::EVRApplicationType, const char*));
+ MAKE_MOCK2(VR_GetGenericInterface, void *(const char *, vr::EVRInitError *));
+ MAKE_MOCK3(VR_InitInternal2, uint32_t(vr::EVRInitError *,
+ vr::EVRApplicationType, const char *));
MAKE_MOCK0(VR_ShutdownInternal, void());
- MAKE_MOCK1(VR_IsInterfaceVersionValid, bool(const char*));
+ MAKE_MOCK1(VR_IsInterfaceVersionValid, bool(const char *));
MAKE_MOCK0(VR_GetInitToken, uint32_t());
};
@@ -52,30 +52,31 @@ namespace vr {
class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
public:
virtual ~IVRSystemMock() = default;
- MAKE_MOCK2(GetRecommendedRenderTargetSize, void(uint32_t*, uint32_t*));
- MAKE_MOCK5(GetProjectionRaw, void(EVREye, float*, float*, float*, float*));
+ MAKE_MOCK2(GetRecommendedRenderTargetSize, void(uint32_t *, uint32_t *));
+ MAKE_MOCK5(GetProjectionRaw,
+ void(EVREye, float *, float *, float *, float *));
MAKE_MOCK4(ComputeDistortion,
- bool(EVREye, float, float, DistortionCoordinates_t*));
- MAKE_MOCK2(GetTimeSinceLastVsync, bool(float*, uint64_t*));
+ bool(EVREye, float, float, DistortionCoordinates_t *));
+ MAKE_MOCK2(GetTimeSinceLastVsync, bool(float *, uint64_t *));
MAKE_MOCK0(GetD3D9AdapterIndex, int32_t());
- MAKE_MOCK1(GetDXGIOutputInfo, void(int32_t*));
- MAKE_MOCK3(GetOutputDevice, void(uint64_t*, ETextureType, VkInstance_T*));
+ MAKE_MOCK1(GetDXGIOutputInfo, void(int32_t *));
+ MAKE_MOCK3(GetOutputDevice, void(uint64_t *, ETextureType, VkInstance_T *));
MAKE_MOCK0(IsDisplayOnDesktop, bool());
MAKE_MOCK1(SetDisplayVisibility, bool(bool));
MAKE_MOCK4(GetDeviceToAbsoluteTrackingPose,
- void(ETrackingUniverseOrigin, float, TrackedDevicePose_t*,
+ void(ETrackingUniverseOrigin, float, TrackedDevicePose_t *,
uint32_t));
MAKE_MOCK0(ResetSeatedZeroPose, void());
MAKE_MOCK0(GetSeatedZeroPoseToStandingAbsoluteTrackingPose, HmdMatrix34_t());
MAKE_MOCK0(GetRawZeroPoseToStandingAbsoluteTrackingPose, HmdMatrix34_t());
MAKE_MOCK4(GetSortedTrackedDeviceIndicesOfClass,
- uint32_t(ETrackedDeviceClass, TrackedDeviceIndex_t*, uint32_t,
+ uint32_t(ETrackedDeviceClass, TrackedDeviceIndex_t *, uint32_t,
TrackedDeviceIndex_t));
MAKE_MOCK1(GetTrackedDeviceActivityLevel,
EDeviceActivityLevel(TrackedDeviceIndex_t));
MAKE_MOCK3(ApplyTransform,
- void(TrackedDevicePose_t*, const TrackedDevicePose_t*,
- const HmdMatrix34_t*));
+ void(TrackedDevicePose_t *, const TrackedDevicePose_t *,
+ const HmdMatrix34_t *));
MAKE_MOCK1(GetTrackedDeviceIndexForControllerRole,
TrackedDeviceIndex_t(vr::ETrackedControllerRole));
MAKE_MOCK1(GetControllerRoleForTrackedDeviceIndex,
@@ -85,43 +86,43 @@ class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
MAKE_MOCK1(IsTrackedDeviceConnected, bool(vr::TrackedDeviceIndex_t));
MAKE_MOCK3(GetBoolTrackedDeviceProperty,
bool(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
- ETrackedPropertyError*));
+ ETrackedPropertyError *));
MAKE_MOCK3(GetFloatTrackedDeviceProperty,
float(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
- ETrackedPropertyError*));
+ ETrackedPropertyError *));
MAKE_MOCK3(GetInt32TrackedDeviceProperty,
int32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
- ETrackedPropertyError*));
+ ETrackedPropertyError *));
MAKE_MOCK3(GetUint64TrackedDeviceProperty,
uint64_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
- ETrackedPropertyError*));
+ ETrackedPropertyError *));
MAKE_MOCK3(GetMatrix34TrackedDeviceProperty,
HmdMatrix34_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty,
- ETrackedPropertyError*));
+ ETrackedPropertyError *));
MAKE_MOCK5(GetStringTrackedDeviceProperty,
- uint32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty, char*,
- uint32_t, ETrackedPropertyError*));
- MAKE_MOCK1(GetPropErrorNameFromEnum, const char*(ETrackedPropertyError));
- MAKE_MOCK2(PollNextEvent, bool(VREvent_t*, uint32_t));
- MAKE_MOCK4(PollNextEventWithPose, bool(ETrackingUniverseOrigin, VREvent_t*,
- uint32_t, vr::TrackedDevicePose_t*));
- MAKE_MOCK1(GetEventTypeNameFromEnum, const char*(EVREventType));
+ uint32_t(vr::TrackedDeviceIndex_t, ETrackedDeviceProperty, char *,
+ uint32_t, ETrackedPropertyError *));
+ MAKE_MOCK1(GetPropErrorNameFromEnum, const char *(ETrackedPropertyError));
+ MAKE_MOCK2(PollNextEvent, bool(VREvent_t *, uint32_t));
+ MAKE_MOCK4(PollNextEventWithPose, bool(ETrackingUniverseOrigin, VREvent_t *,
+ uint32_t, vr::TrackedDevicePose_t *));
+ MAKE_MOCK1(GetEventTypeNameFromEnum, const char *(EVREventType));
MAKE_MOCK2(GetHiddenAreaMesh, HiddenAreaMesh_t(EVREye, EHiddenAreaMeshType));
MAKE_MOCK3(GetControllerState, bool(vr::TrackedDeviceIndex_t,
- vr::VRControllerState_t*, uint32_t));
+ vr::VRControllerState_t *, uint32_t));
MAKE_MOCK5(GetControllerStateWithPose,
bool(ETrackingUniverseOrigin, vr::TrackedDeviceIndex_t,
- vr::VRControllerState_t*, uint32_t, TrackedDevicePose_t*));
+ vr::VRControllerState_t *, uint32_t, TrackedDevicePose_t *));
MAKE_MOCK3(TriggerHapticPulse,
void(vr::TrackedDeviceIndex_t, uint32_t, unsigned short));
- MAKE_MOCK1(GetButtonIdNameFromEnum, const char*(EVRButtonId));
+ MAKE_MOCK1(GetButtonIdNameFromEnum, const char *(EVRButtonId));
MAKE_MOCK1(GetControllerAxisTypeNameFromEnum,
- const char*(EVRControllerAxisType));
+ const char *(EVRControllerAxisType));
MAKE_MOCK0(CaptureInputFocus, bool());
MAKE_MOCK0(ReleaseInputFocus, void());
MAKE_MOCK0(IsInputFocusCapturedByAnotherProcess, bool());
- MAKE_MOCK4(DriverDebugRequest,
- uint32_t(vr::TrackedDeviceIndex_t, const char*, char*, uint32_t));
+ MAKE_MOCK4(DriverDebugRequest, uint32_t(vr::TrackedDeviceIndex_t,
+ const char *, char *, uint32_t));
MAKE_MOCK1(PerformFirmwareUpdate,
vr::EVRFirmwareError(vr::TrackedDeviceIndex_t));
MAKE_MOCK0(AcknowledgeQuit_Exiting, void());
@@ -130,9 +131,9 @@ class OPENVR_MOCK_EXPORT IVRSystemMock : public IVRSystem {
// somehow returning structs is a problem, so this workaround
// TODO(WJ): should be reworked once this is solved in trompeloeil
// https://github.com/rollbear/trompeloeil/issues/69
- MAKE_MOCK3(GetProjectionMatrixArray, float*(vr::EVREye, float, float));
+ MAKE_MOCK3(GetProjectionMatrixArray, float *(vr::EVREye, float, float));
vr::HmdMatrix44_t GetProjectionMatrix(vr::EVREye, float, float);
- MAKE_MOCK1(GetEyeToHeadTransformArray, float*(EVREye));
+ MAKE_MOCK1(GetEyeToHeadTransformArray, float *(EVREye));
HmdMatrix34_t GetEyeToHeadTransform(EVREye);
};
@@ -140,27 +141,28 @@ class OPENVR_MOCK_EXPORT IVRCompositorMock : public IVRCompositor {
public:
MAKE_MOCK1(SetTrackingSpace, void(ETrackingUniverseOrigin));
MAKE_MOCK0(GetTrackingSpace, ETrackingUniverseOrigin());
- MAKE_MOCK4(WaitGetPoses, EVRCompositorError(TrackedDevicePose_t*, uint32_t,
- TrackedDevicePose_t*, uint32_t));
- MAKE_MOCK4(GetLastPoses, EVRCompositorError(TrackedDevicePose_t*, uint32_t,
- TrackedDevicePose_t*, uint32_t));
+ MAKE_MOCK4(WaitGetPoses, EVRCompositorError(TrackedDevicePose_t *, uint32_t,
+ TrackedDevicePose_t *, uint32_t));
+ MAKE_MOCK4(GetLastPoses, EVRCompositorError(TrackedDevicePose_t *, uint32_t,
+ TrackedDevicePose_t *, uint32_t));
MAKE_MOCK3(GetLastPoseForTrackedDeviceIndex,
- EVRCompositorError(TrackedDeviceIndex_t, TrackedDevicePose_t*,
- TrackedDevicePose_t*));
+ EVRCompositorError(TrackedDeviceIndex_t, TrackedDevicePose_t *,
+ TrackedDevicePose_t *));
MAKE_MOCK4(Submit,
- EVRCompositorError(EVREye, const Texture_t*,
- const VRTextureBounds_t*, EVRSubmitFlags));
+ EVRCompositorError(EVREye, const Texture_t *,
+ const VRTextureBounds_t *, EVRSubmitFlags));
MAKE_MOCK0(ClearLastSubmittedFrame, void());
MAKE_MOCK0(PostPresentHandoff, void());
- MAKE_MOCK2(GetFrameTiming, bool(Compositor_FrameTiming*, uint32_t));
- MAKE_MOCK2(GetFrameTimings, uint32_t(Compositor_FrameTiming*, uint32_t));
+ MAKE_MOCK2(GetFrameTiming, bool(Compositor_FrameTiming *, uint32_t));
+ MAKE_MOCK2(GetFrameTimings, uint32_t(Compositor_FrameTiming *, uint32_t));
MAKE_MOCK0(GetFrameTimeRemaining, float());
- MAKE_MOCK2(GetCumulativeStats, void(Compositor_CumulativeStats*, uint32_t));
+ MAKE_MOCK2(GetCumulativeStats, void(Compositor_CumulativeStats *, uint32_t));
MAKE_MOCK6(FadeToColor, void(float, float, float, float, float, bool));
MAKE_MOCK1(GetCurrentFadeColor, HmdColor_t(bool));
MAKE_MOCK2(FadeGrid, void(float, bool));
MAKE_MOCK0(GetCurrentGridAlpha, float());
- MAKE_MOCK2(SetSkyboxOverride, EVRCompositorError(const Texture_t*, uint32_t));
+ MAKE_MOCK2(SetSkyboxOverride,
+ EVRCompositorError(const Texture_t *, uint32_t));
MAKE_MOCK0(ClearSkyboxOverride, void());
MAKE_MOCK0(CompositorBringToFront, void());
MAKE_MOCK0(CompositorGoToBack, void());
@@ -178,22 +180,62 @@ class OPENVR_MOCK_EXPORT IVRCompositorMock : public IVRCompositor {
MAKE_MOCK0(ForceReconnectProcess, void());
MAKE_MOCK1(SuspendRendering, void(bool));
MAKE_MOCK3(GetMirrorTextureD3D11,
- EVRCompositorError(vr::EVREye, void*, void**));
- MAKE_MOCK1(ReleaseMirrorTextureD3D11, void(void*));
+ EVRCompositorError(vr::EVREye, void *, void **));
+ MAKE_MOCK1(ReleaseMirrorTextureD3D11, void(void *));
MAKE_MOCK3(GetMirrorTextureGL,
- vr::EVRCompositorError(vr::EVREye, vr::glUInt_t*,
- vr::glSharedTextureHandle_t*));
+ vr::EVRCompositorError(vr::EVREye, vr::glUInt_t *,
+ vr::glSharedTextureHandle_t *));
MAKE_MOCK2(ReleaseSharedGLTexture,
bool(vr::glUInt_t, vr::glSharedTextureHandle_t));
MAKE_MOCK1(LockGLSharedTextureForAccess, void(vr::glSharedTextureHandle_t));
MAKE_MOCK1(UnlockGLSharedTextureForAccess, void(vr::glSharedTextureHandle_t));
- MAKE_MOCK2(GetVulkanInstanceExtensionsRequired, uint32_t(char*, uint32_t));
+ MAKE_MOCK2(GetVulkanInstanceExtensionsRequired, uint32_t(char *, uint32_t));
MAKE_MOCK3(GetVulkanDeviceExtensionsRequired,
- uint32_t(VkPhysicalDevice_T*, char*, uint32_t));
+ uint32_t(VkPhysicalDevice_T *, char *, uint32_t));
MAKE_MOCK1(SetExplicitTimingMode, void(bool));
MAKE_MOCK0(SubmitExplicitTimingData, EVRCompositorError());
};
+class OPENVR_MOCK_EXPORT IVRRenderModelsMock : public IVRRenderModels {
+ public:
+ MAKE_MOCK2(LoadRenderModel_Async,
+ EVRRenderModelError(const char *, RenderModel_t **));
+ MAKE_MOCK1(FreeRenderModel, void(RenderModel_t *));
+ MAKE_MOCK2(LoadTexture_Async,
+ EVRRenderModelError(TextureID_t, RenderModel_TextureMap_t **));
+ MAKE_MOCK1(FreeTexture, void(RenderModel_TextureMap_t *));
+ MAKE_MOCK3(LoadTextureD3D11_Async,
+ EVRRenderModelError(TextureID_t, void *, void **));
+ MAKE_MOCK2(LoadIntoTextureD3D11_Async,
+ EVRRenderModelError(TextureID_t, void *));
+ MAKE_MOCK1(FreeTextureD3D11, void(void *));
+ MAKE_MOCK3(GetRenderModelName,
+ uint32_t(uint32_t, VR_OUT_STRING() char *, uint32_t));
+ MAKE_MOCK0(GetRenderModelCount, uint32_t());
+ MAKE_MOCK1(GetComponentCount, uint32_t(const char *));
+ MAKE_MOCK4(GetComponentName, uint32_t(const char *, uint32_t,
+ VR_OUT_STRING() char *, uint32_t));
+
+ MAKE_MOCK2(GetComponentButtonMask, uint64_t(const char *, const char *));
+ MAKE_MOCK4(GetComponentRenderModelName,
+ uint32_t(const char *, const char *, VR_OUT_STRING() char *,
+ uint32_t));
+ MAKE_MOCK5(GetComponentState,
+ bool(const char *, const char *, const vr::VRControllerState_t *,
+ const RenderModel_ControllerMode_State_t *,
+ RenderModel_ComponentState_t *));
+
+ MAKE_MOCK2(RenderModelHasComponent, bool(const char *, const char *));
+ MAKE_MOCK4(GetRenderModelThumbnailURL,
+ uint32_t(const char *, VR_OUT_STRING() char *, uint32_t,
+ vr::EVRRenderModelError *));
+ MAKE_MOCK4(GetRenderModelOriginalPath,
+ uint32_t(const char *, VR_OUT_STRING() char *, uint32_t,
+ vr::EVRRenderModelError *));
+ MAKE_MOCK1(GetRenderModelErrorNameFromEnum,
+ const char *(vr::EVRRenderModelError));
+};
+
} // namespace vr
class OPENVR_MOCK_EXPORT OpenVRMock {
@@ -201,7 +243,8 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
OpenVRMock()
: mock_(new OpenVRMockInternal),
ivr_system_mock_(new vr::IVRSystemMock),
- ivr_compositor_mock_(new vr::IVRCompositorMock) {}
+ ivr_compositor_mock_(new vr::IVRCompositorMock),
+ ivr_render_models_mock_(new vr::IVRRenderModelsMock) {}
~OpenVRMock() {
// We have to leak the mock_ pointer for the time being.
// see
@@ -209,9 +252,35 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
// TODO(@tvierjahn) regularly check progress on this issue
}
- OpenVRMockInternal& Get() { return *mock_; }
- vr::IVRSystemMock& GetSystem() const { return *ivr_system_mock_; }
- vr::IVRCompositorMock& GetCompositor() { return *ivr_compositor_mock_; }
+ OpenVRMockInternal &Get() { return *mock_; }
+ vr::IVRSystemMock &GetSystem() const { return *ivr_system_mock_; }
+ vr::IVRCompositorMock &GetCompositor() { return *ivr_compositor_mock_; }
+ vr::IVRRenderModelsMock &GetRenderModels() {
+ return *ivr_render_models_mock_;
+ }
+
+ static vr::RenderModel_t *CreateDummyTriangleModel() {
+ vr::RenderModel_t *model = new vr::RenderModel_t();
+ model->rIndexData = new uint16_t[3]{0, 1, 2};
+ model->unVertexCount = 3;
+ model->unTriangleCount = 1;
+ model->diffuseTextureId = -1;
+
+ vr::RenderModel_Vertex_t vertex1;
+ vertex1.vPosition = {{-0.1f, -0.1f, 0.f}};
+ vertex1.vNormal = {{0.f, 0.f, 1.f}};
+ vertex1.rfTextureCoord[0] = 0.f;
+ vertex1.rfTextureCoord[1] = 0.f;
+ vr::RenderModel_Vertex_t vertex2 = vertex1;
+ vertex2.vPosition = {{+0.1f, -0.1f, 0.f}};
+ vr::RenderModel_Vertex_t vertex3 = vertex1;
+ vertex2.vPosition = {{0.f, +0.1f, 0.f}};
+
+ model->rVertexData =
+ new vr::RenderModel_Vertex_t[3]{vertex1, vertex2, vertex3};
+
+ return model;
+ }
static vr::HmdMatrix44_t toHMDMatrix44_t(float mat[16]);
static vr::HmdMatrix34_t toHMDMatrix34_t(float mat[12]);
@@ -229,9 +298,10 @@ class OPENVR_MOCK_EXPORT OpenVRMock {
0.0f, 1.8f, 0.0f, 0.0f, 1.0f, 0.0f};
private:
- OpenVRMockInternal* mock_;
- vr::IVRSystemMock* ivr_system_mock_;
- vr::IVRCompositorMock* ivr_compositor_mock_;
+ OpenVRMockInternal *mock_;
+ vr::IVRSystemMock *ivr_system_mock_;
+ vr::IVRCompositorMock *ivr_compositor_mock_;
+ vr::IVRRenderModelsMock *ivr_render_models_mock_;
};
extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
@@ -251,12 +321,14 @@ extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
.RETURN(openvr_mock.eye_to_head_right_); \
ALLOW_CALL(openvr_mock.GetSystem(), \
GetSortedTrackedDeviceIndicesOfClass(_, _, _, _)) \
- .RETURN(0u); \
+ .RETURN(2u) \
+ .SIDE_EFFECT(*_2 = 0u) \
+ .SIDE_EFFECT(*(_2 + sizeof(vr::TrackedDeviceIndex_t)) = 1u); \
ALLOW_CALL(openvr_mock.GetSystem(), \
- GetControllerRoleForTrackedDeviceIndex(_)) \
+ GetControllerRoleForTrackedDeviceIndex(0u)) \
.RETURN(vr::TrackedControllerRole_LeftHand); \
ALLOW_CALL(openvr_mock.GetSystem(), \
- GetControllerRoleForTrackedDeviceIndex(_)) \
+ GetControllerRoleForTrackedDeviceIndex(1u)) \
.RETURN(vr::TrackedControllerRole_RightHand); \
ALLOW_CALL(openvr_mock.GetCompositor(), WaitGetPoses(_, _, _, _)) \
.RETURN(vr::EVRCompositorError::VRCompositorError_None) \
@@ -268,16 +340,28 @@ extern OPENVR_MOCK_EXPORT OpenVRMock openvr_mock;
.RETURN(vr::EVRCompositorError::VRCompositorError_None); \
ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _)) \
.WITH(std::string(vr::IVRSystem_Version) == std::string(_1)) \
- .RETURN(static_cast<void*>(&openvr_mock.GetSystem())); \
+ .RETURN(static_cast<void *>(&openvr_mock.GetSystem())); \
+ ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _)) \
+ .WITH(std::string(vr::IVRRenderModels_Version) == std::string(_1)) \
+ .RETURN(static_cast<void *>(&openvr_mock.GetRenderModels())); \
ALLOW_CALL(openvr_mock.Get(), VR_GetGenericInterface(_, _)) \
.WITH(std::string(vr::IVRCompositor_Version) == std::string(_1)) \
- .RETURN(static_cast<void*>(&openvr_mock.GetCompositor())); \
+ .RETURN(static_cast<void *>(&openvr_mock.GetCompositor())); \
ALLOW_CALL(openvr_mock.Get(), \
VR_InitInternal2(_, vr::VRApplication_Scene, _)) \
.RETURN(static_cast<uint32_t>(1337)) \
.SIDE_EFFECT(*_1 = vr::VRInitError_None); \
ALLOW_CALL(openvr_mock.Get(), VR_ShutdownInternal()); \
ALLOW_CALL(openvr_mock.Get(), VR_IsInterfaceVersionValid(_)).RETURN(true); \
- ALLOW_CALL(openvr_mock.Get(), VR_GetInitToken()).RETURN(1337);
+ ALLOW_CALL(openvr_mock.Get(), VR_GetInitToken()).RETURN(1337); \
+ ALLOW_CALL(openvr_mock.GetRenderModels(), LoadRenderModel_Async(_, _)) \
+ .RETURN(vr::VRRenderModelError_None) \
+ .SIDE_EFFECT(*_2 = openvr_mock.CreateDummyTriangleModel()); \
+ ALLOW_CALL(openvr_mock.GetSystem(), \
+ GetStringTrackedDeviceProperty(_, _, _, _, _)) \
+ .RETURN(0); \
+ ALLOW_CALL(openvr_mock.GetRenderModels(), LoadTexture_Async(_, _)) \
+ .RETURN(vr::VRRenderModelError_None) \
+ .SIDE_EFFECT(*_2 = nullptr);
#endif // TESTS_SRC_MOCKS_OPENVR_MOCK_HPP_
diff --git a/tests/src/test_engine.cpp b/tests/src/test_engine.cpp
index 9ebc1171eebd2256c1f87887f8381b3c8790ad22..f8a7baf5c5e313fd405ed9ca22895433af8bfaad 100644
--- a/tests/src/test_engine.cpp
+++ b/tests/src/test_engine.cpp
@@ -41,9 +41,7 @@
#include "trompeloeil.hpp"
-SUPPRESS_WARNINGS_BEGIN
#include "mocks/openvr_mock.hpp"
-SUPPRESS_WARNINGS_END
#include "mocks/opengl_mock.hpp"
#include "mocks/sdl_mock.hpp"
diff --git a/tests/src/test_openvr_controller_system.cpp b/tests/src/test_openvr_controller_system.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..225ea9b498109211629d506451deb94b6834fde4
--- /dev/null
+++ b/tests/src/test_openvr_controller_system.cpp
@@ -0,0 +1,118 @@
+//------------------------------------------------------------------------------
+// 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 <memory>
+
+#include "catch/catch.hpp"
+
+SUPPRESS_WARNINGS_BEGIN
+#include "GL/glew.h"
+SUPPRESS_WARNINGS_END
+
+#include "trompeloeil.hpp"
+
+#include "phx/display_system_openvr.hpp"
+#include "phx/entity.hpp"
+#include "phx/material_handle.hpp"
+#include "phx/mesh_handle.hpp"
+#include "phx/openvr_controller_behavior.hpp"
+#include "phx/openvr_controller_system.hpp"
+#include "phx/rendering_system.hpp"
+#include "phx/scene.hpp"
+
+#include "mocks/opengl_mock.hpp"
+#include "mocks/openvr_mock.hpp"
+#include "mocks/sdl_mock.hpp"
+
+using trompeloeil::_;
+using trompeloeil::ne;
+
+extern template struct trompeloeil::reporter<trompeloeil::specialized>;
+
+class EngineStopTestSystem : public phx::System {
+ public:
+ explicit EngineStopTestSystem(phx::Engine* engine, int stop_in_frame = 1)
+ : System(engine), stop_on_update_(stop_in_frame) {}
+
+ void Update(const phx::FrameTimer::TimeInfo& time_info) override {
+ update_counter_++;
+ if (update_counter_ >= stop_on_update_) {
+ GetEngine()->Stop();
+ }
+ time_info_ = &time_info;
+ }
+
+ const phx::FrameTimer::TimeInfo* time_info_ = nullptr;
+
+ private:
+ int update_counter_ = 0;
+ int stop_on_update_ = 1;
+};
+
+SCENARIO(
+ "The OpenVRControllerSystem automatically inserts controller entities into "
+ "a scene if controllers are connected",
+ "[phx][phx::OpenVRControllerSystem]") {
+ OPENGL_MOCK_ALLOW_ANY_CALL;
+ OPENVR_MOCK_ALLOW_ANY_CALL;
+ SDL_MOCK_ALLOW_ANY_CALL;
+
+ phx::Engine engine;
+ auto display_system = engine.CreateSystem<phx::DisplaySystemOpenVR>();
+
+ GIVEN(
+ "The display system has an HMD and the engine has a scene. Also, there's "
+ "an OpenVRControllerSystem.") {
+ display_system->CreateHMD();
+ auto scene = std::make_shared<phx::Scene>();
+ engine.SetScene(scene);
+ engine.CreateSystem<phx::OpenVRControllerSystem>(display_system);
+ engine.CreateSystem<EngineStopTestSystem>();
+ engine.CreateSystem<phx::RenderingSystem>(display_system);
+
+ WHEN("We run the engine for once frame (updating each system once)") {
+ engine.Run();
+
+ THEN(
+ "There are controller entities in the scene with controller "
+ "behaviors attached to them, as well as mesh and material handles, "
+ "and the controllers are left and right") {
+ auto controller_entities =
+ scene->GetEntitiesWithComponents<phx::OpenVRControllerBehavior>();
+ REQUIRE(controller_entities.size() == 2);
+
+ for (auto entity : controller_entities) {
+ REQUIRE(entity->GetFirstComponent<phx::MeshHandle>() != nullptr);
+ REQUIRE(entity->GetFirstComponent<phx::MaterialHandle>() != nullptr);
+ }
+
+ auto side0 = controller_entities[0]
+ ->GetFirstComponent<phx::OpenVRControllerBehavior>()
+ ->GetSide();
+ auto side1 = controller_entities[1]
+ ->GetFirstComponent<phx::OpenVRControllerBehavior>()
+ ->GetSide();
+ REQUIRE(side0 != side1);
+ }
+ }
+ }
+}