use "mspgame";
require "mspgui";
require "mspgl";
+ require "mspvr";
install true;
install_map
{
#include <msp/gl/windowview.h>
#include <msp/graphics/display.h>
#include <msp/graphics/window.h>
+#include <msp/vr/system.h>
#include "playerinput.h"
#include "presenter.h"
ResourcesType resources;
Game::Director director;
GL::WindowView gl_view;
+ std::unique_ptr<VR::System> vr_system;
Presenter presenter;
PlayerInput player_input;
int main() override;
protected:
void tick() override;
+
+ bool try_enable_vr();
};
template<typename T, typename R>
director.tick();
}
+template<typename T, typename R>
+bool Application<T, R>::try_enable_vr()
+{
+ vr_system = VR::System::create_autodetect();
+ if(vr_system)
+ {
+ player_input.enable_vr(*vr_system);
+ presenter.enable_vr(*vr_system);
+ }
+ return static_cast<bool>(vr_system);
+}
+
} // namespace Msp::GameView
#endif
--- /dev/null
+#include "motiontracker.h"
+#include <msp/game/root.h>
+#include <msp/game/transform.h>
+
+using namespace std;
+
+namespace Msp::GameView {
+
+MotionTracker::MotionTracker(Game::Stage &s):
+ System(s)
+{
+ declare_dependency<Game::Transform>(WRITE);
+}
+
+void MotionTracker::track(const VR::HeadTrackingCamera &cam)
+{
+ Part &part = get_or_create_part(TrackedElement::HEAD);
+ part.head = &cam;
+}
+
+void MotionTracker::track(const VR::MotionController &ctrl)
+{
+ TrackedElement::Role role;
+ switch(ctrl.get_role())
+ {
+ case VR::LEFT_HAND: role = TrackedElement::LEFT_HAND; break;
+ case VR::RIGHT_HAND: role = TrackedElement::RIGHT_HAND; break;
+ default: throw invalid_argument("MotionTracker::track");
+ }
+
+ Part &part = get_or_create_part(role);
+ part.controller = &ctrl;
+}
+
+auto MotionTracker::get_or_create_part(TrackedElement::Role role) -> Part &
+{
+ auto i = find_if(parts, [role](const Part &p){ return p.element->get_role()==role; });
+ if(i!=parts.end())
+ return *i;
+
+ Part &part = parts.emplace_back();
+ part.entity = Game::Owned<Game::Entity>(stage.get_root(), Game::TransformValues());
+ part.element = Game::Owned<TrackedElement>(part.entity, role);
+
+ return part;
+}
+
+void MotionTracker::tick(Time::TimeDelta)
+{
+ for(const Part &p: parts)
+ {
+ GL::Matrix matrix;
+ if(p.head)
+ matrix = p.head->get_object_matrix();
+ else if(p.controller)
+ matrix = p.controller->get_matrix();
+ else
+ continue;
+
+ p.entity->get_transform()->set_values(Game::TransformValues::from_matrix(matrix));
+ }
+}
+
+} // namespace Msp::GameView
--- /dev/null
+#ifndef MSP_GAMEVIEW_MOTIONTRACKER_H_
+#define MSP_GAMEVIEW_MOTIONTRACKER_H_
+
+#include <msp/game/owned.h>
+#include <msp/game/system.h>
+#include <msp/vr/headtrackingcamera.h>
+#include <msp/vr/motioncontroller.h>
+#include "trackedelement.h"
+
+namespace Msp::GameView {
+
+class MSPGAMEVIEW_API MotionTracker: public Game::System
+{
+private:
+ struct Part
+ {
+ const VR::HeadTrackingCamera *head = nullptr;
+ const VR::MotionController *controller = nullptr;
+ Game::Owned<Game::Entity> entity;
+ Game::Owned<TrackedElement> element;
+ };
+
+ std::vector<Part> parts;
+
+public:
+ MotionTracker(Game::Stage &);
+
+ void track(const VR::HeadTrackingCamera &);
+ void track(const VR::MotionController &);
+private:
+ Part &get_or_create_part(TrackedElement::Role);
+
+public:
+ void tick(Time::TimeDelta) override;
+};
+
+} // namespace Msp::GameView
+
+#endif
bindings = director.get_resources().get_all<Input::Bindings>();
}
+void PlayerInput::enable_vr(VR::System &vr_sys)
+{
+ vr_controllers.push_back(vr_sys.create_controller(VR::LEFT_HAND));
+ vr_controllers.push_back(vr_sys.create_controller(VR::RIGHT_HAND));
+ for(const auto &c: vr_controllers)
+ vr_hub.attach(*c);
+}
+
void PlayerInput::init_players()
{
- add_player(kbm_hub);
+ if(!vr_controllers.empty())
+ add_player(vr_hub);
+ else
+ add_player(kbm_hub);
}
void PlayerInput::add_player(Input::Device &dev)
#include <msp/input/keyboard.h>
#include <msp/input/mouse.h>
#include <msp/game/director.h>
+#include <msp/vr/motioncontroller.h>
+#include <msp/vr/system.h>
#include "events.h"
#include "mspgameview_api.h"
Input::Keyboard keyboard;
Input::Mouse mouse;
Input::Hub kbm_hub;
+ std::vector<std::unique_ptr<VR::MotionController>> vr_controllers;
+ Input::Hub vr_hub;
std::vector<Input::Bindings *> bindings;
SchemeFactoryFunc *scheme_factory = nullptr;
std::vector<Player> players;
public:
PlayerInput(Game::Director &, Graphics::Window &);
+ void enable_vr(VR::System &);
+
template<typename T>
requires std::is_base_of_v<Input::ControlScheme, T>
void set_control_scheme_type(Mode = ONE_LOCAL_PLAYER);
#include <msp/game/events.h>
#include <msp/game/landscape.h>
#include <msp/game/stage.h>
+#include "motiontracker.h"
#include "renderer.h"
#include "terrainmeshcreator.h"
resources(director.get_resources()),
event_observer(director.get_event_bus())
{
+ event_observer.observe<Events::LocalPlayerArrived>([this](auto &e){ player_arrived(e); });
event_observer.observe<Game::Events::StageActivated>([this](auto &e){ stage_activated(e); });
if(Game::Stage *active_stage = director.get_active_stage())
s->get_stage().remove_system(*s);
}
+void Presenter::enable_vr(VR::System &vr_sys)
+{
+ vr_system = &vr_sys;
+ if(active_renderer)
+ stage_activated({ active_renderer->get_stage() });
+}
+
+void Presenter::player_arrived(const Events::LocalPlayerArrived &event)
+{
+ for(unsigned i=0;; ++i)
+ {
+ Input::Device *dev = event.device.find_subdevice(VR::VR_CONTROLLER, i);
+ if(!dev)
+ break;
+
+ VR::MotionController *vr_ctrl = dynamic_cast<VR::MotionController *>(dev);
+ if(vr_ctrl)
+ vr_controllers.push_back(vr_ctrl);
+ }
+}
+
void Presenter::stage_activated(const Game::Events::StageActivated &event)
{
if(active_renderer)
active_renderer = event.stage.get_system<Renderer>();
if(!active_renderer)
systems.push_back(active_renderer = &event.stage.add_system<Renderer>());
+ MotionTracker *tracker = nullptr;
+ if(vr_system)
+ {
+ tracker = event.stage.get_system<MotionTracker>();
+ if(!tracker)
+ {
+ systems.push_back(tracker = &event.stage.add_system<MotionTracker>());
+ for(VR::MotionController *c: vr_controllers)
+ tracker->track(*c);
+ }
+ }
if(event.stage.get_system<Game::Landscape>() && !event.stage.get_system<TerrainMeshCreator>())
systems.push_back(&event.stage.add_system<TerrainMeshCreator>());
if(active_renderer)
- active_renderer->output_to_view(gl_view);
+ {
+ if(vr_system)
+ {
+ VR::StereoView *view = active_renderer->output_to_vr(*vr_system, gl_view);
+ vr_system->set_tracking_view(view);
+ if(const VR::HeadTrackingCamera *head = view->get_head_camera())
+ tracker->track(*head);
+ }
+ else
+ active_renderer->output_to_view(gl_view);
+ }
}
} // namespace Msp::GameView
#include <msp/game/eventobserver.h>
#include <msp/game/system.h>
#include <msp/gl/view.h>
+#include <msp/vr/system.h>
+#include "events.h"
#include "mspgameview_api.h"
namespace Msp::GameView {
private:
Game::Director &director;
GL::View &gl_view;
+ VR::System *vr_system = nullptr;
DataFile::Collection &resources;
Game::EventObserver event_observer;
std::vector<Game::System *> systems;
Renderer *active_renderer = nullptr;
+ std::vector<VR::MotionController *> vr_controllers;
public:
Presenter(Game::Director &, GL::View &);
~Presenter();
+ void enable_vr(VR::System &);
+
private:
+ void player_arrived(const Events::LocalPlayerArrived &);
void stage_activated(const Game::Events::StageActivated &);
};
create_sequence();
}
+VR::StereoView *Renderer::output_to_vr(VR::System &vr_sys, GL::View &view)
+{
+ cancel_output();
+ vr_view = vr_sys.create_view(view, gl_camera);
+ if(active_camera)
+ create_sequence();
+ return vr_view.get();
+}
+
void Renderer::cancel_output()
{
if(gl_view)
gl_view->set_content(nullptr);
gl_view->set_camera(nullptr);
}
+ vr_view = nullptr;
sequence = nullptr;
}
void Renderer::create_sequence()
{
unsigned w, h;
- if(gl_view)
+ if(vr_view)
+ {
+ w = vr_view->get_render_width();
+ h = vr_view->get_render_height();
+ }
+ else if(gl_view)
{
w = gl_view->get_width();
h = gl_view->get_height();
sequence->add_postprocessor(*colorcurve);
sequence->add_owned(colorcurve.release());
- gl_view->set_content(sequence.get());
+ if(vr_view)
+ vr_view->set_content(sequence.get());
+ else
+ gl_view->set_content(sequence.get());
}
void Renderer::component_created(const Game::Events::ComponentCreated &event)
void Renderer::camera_changed(const Game::Events::CameraChanged &event)
{
active_camera = event.camera;
- if(active_camera && gl_view)
+ if(active_camera && (gl_view || vr_view))
create_sequence();
}
stage.iterate_objects<MeshRenderer>([](MeshRenderer &m){ m.update_matrix(); });
stage.iterate_objects<LightEmitter>([](LightEmitter &e){ e.update_matrix(); });
- if(gl_view)
+ if(vr_view)
+ vr_view->render();
+ else if(gl_view)
gl_view->render();
}
#include <msp/gl/simplescene.h>
#include <msp/gl/slot.h>
#include <msp/gl/view.h>
+#include <msp/vr/stereoview.h>
+#include <msp/vr/system.h>
#include "mspgameview_api.h"
namespace Msp::GameView {
unsigned shadow_base_size = 4096;
bool shadows_changed = false;
GL::View *gl_view = nullptr;
+ std::unique_ptr<VR::StereoView> vr_view;
public:
Renderer(Game::Stage &);
~Renderer();
void output_to_view(GL::View &);
+ VR::StereoView *output_to_vr(VR::System &, GL::View &);
void cancel_output();
private:
void create_sequence();
#ifndef MSP_GAMEVIEW_RESOURCES_H_
#define MSP_GAMEVIEW_RESOURCES_H_
-#include <msp/gl/resources.h>
+#include <msp/vr/resources.h>
#include "mspgameview_api.h"
namespace Msp::GameView {
-class MSPGAMEVIEW_API Resources: public GL::Resources
+class MSPGAMEVIEW_API Resources: public VR::Resources
{
public:
Resources();
--- /dev/null
+#include "trackedelement.h"
+
+namespace Msp::GameView {
+
+TrackedElement::TrackedElement(Game::Handle<Game::Entity> p, Role r):
+ Component(p),
+ role(r)
+{ }
+
+} // namespace Msp::GameView
--- /dev/null
+#ifndef MSP_GAMEVIEW_TRACKEDELEMENT_H_
+#define MSP_GAMEVIEW_TRACKEDELEMENT_H_
+
+#include <msp/game/component.h>
+#include "mspgameview_api.h"
+
+namespace Msp::GameView {
+
+class MSPGAMEVIEW_API TrackedElement: public Game::Component
+{
+public:
+ enum Role
+ {
+ HEAD,
+ LEFT_HAND,
+ RIGHT_HAND
+ };
+
+private:
+ Role role;
+
+public:
+ TrackedElement(Game::Handle<Game::Entity>, Role);
+
+ Role get_role() const { return role; }
+};
+
+} // namespace Msp::GameView
+
+#endif