diff options
Diffstat (limited to 'support/magicleap/Servo2D/code')
-rw-r--r-- | support/magicleap/Servo2D/code/inc.gen/SceneDescriptor.h | 48 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/inc.gen/scenesGen.h | 34 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/inc/Servo2D.h | 108 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/src.gen/SceneDescriptor.cpp | 54 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/src.gen/scenesGen.cpp | 49 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/src/Servo2D.cpp | 264 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/src/main.cpp | 13 | ||||
-rw-r--r-- | support/magicleap/Servo2D/code/srcsGen.comp | 3 |
8 files changed, 573 insertions, 0 deletions
diff --git a/support/magicleap/Servo2D/code/inc.gen/SceneDescriptor.h b/support/magicleap/Servo2D/code/inc.gen/SceneDescriptor.h new file mode 100644 index 00000000000..db950700a13 --- /dev/null +++ b/support/magicleap/Servo2D/code/inc.gen/SceneDescriptor.h @@ -0,0 +1,48 @@ +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- +// +// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND +// ANY MODIFICATIONS WILL BE OVERWRITTEN +// +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- + +// %BANNER_BEGIN% +// --------------------------------------------------------------------- +// %COPYRIGHT_BEGIN% +// +// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved. +// Use of this file is governed by the Creator Agreement, located +// here: https://id.magicleap.com/creator-terms +// +// %COPYRIGHT_END% +// --------------------------------------------------------------------- +// %BANNER_END% + +#pragma once + +#include <string> +#include <map> + +// data class +class SceneDescriptor { + public: + + typedef std::map<std::string /* exportedNodeName */, const std::string& /* exportedNodeId */> ExportedNodeReferences; + + SceneDescriptor(const char* exportedName, const char* id, const char* sceneGraphFilePath, const char* resourceModelFilePath, const ExportedNodeReferences& exportedNodeReferences, bool initiallyInstanced); + const std::string& getExportedName() const; + const std::string& getId() const; + const std::string& getSceneGraphPath() const; + const std::string& getResourceModelPath() const; + const ExportedNodeReferences & getExportedNodeReferences() const; + bool getInitiallyInstanced() const; + + private: + std::string exportedName_; + std::string id_; + std::string sceneGraphPath_; + std::string resourceModelPath_; + const ExportedNodeReferences& exportedNodeReferences_; + bool initiallyInstanced_; +}; + +typedef std::map<std::string /* exportedName */, const SceneDescriptor&> SceneDescriptorReferences; diff --git a/support/magicleap/Servo2D/code/inc.gen/scenesGen.h b/support/magicleap/Servo2D/code/inc.gen/scenesGen.h new file mode 100644 index 00000000000..eae1ce2e957 --- /dev/null +++ b/support/magicleap/Servo2D/code/inc.gen/scenesGen.h @@ -0,0 +1,34 @@ +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- +// +// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND +// ANY MODIFICATIONS WILL BE OVERWRITTEN +// +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- + +// %BANNER_BEGIN% +// --------------------------------------------------------------------- +// %COPYRIGHT_BEGIN% +// +// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved. +// Use of this file is governed by the Creator Agreement, located +// here: https://id.magicleap.com/creator-terms +// +// %COPYRIGHT_END% +// --------------------------------------------------------------------- +// %BANNER_END% + +#pragma once + +#include <SceneDescriptor.h> + +namespace Servo2D_exportedNodes { + extern const std::string content; + extern const std::string backButton; + extern const std::string fwdButton; + extern const std::string urlBar; +} + +namespace scenes { + extern const SceneDescriptor Servo2D; + extern const SceneDescriptorReferences exportedScenes; +} diff --git a/support/magicleap/Servo2D/code/inc/Servo2D.h b/support/magicleap/Servo2D/code/inc/Servo2D.h new file mode 100644 index 00000000000..2f76c306e7c --- /dev/null +++ b/support/magicleap/Servo2D/code/inc/Servo2D.h @@ -0,0 +1,108 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <lumin/LandscapeApp.h> +#include <lumin/Prism.h> +#include <lumin/event/ServerEvent.h> +#include <lumin/event/KeyInputEventData.h> +#include <lumin/event/ControlTouchPadInputEventData.h> +#include <lumin/node/QuadNode.h> +#include <lumin/resource/PlanarResource.h> +#include <SceneDescriptor.h> + +typedef void* ServoInstance; + +/** + * Servo2D Landscape Application + */ +class Servo2D : public lumin::LandscapeApp { +public: + /** + * Constructs the Landscape Application. + */ + Servo2D(); + + /** + * Destroys the Landscape Application. + */ + virtual ~Servo2D(); + + /** + * Disallows the copy constructor. + */ + Servo2D(const Servo2D&) = delete; + + /** + * Disallows the move constructor. + */ + Servo2D(Servo2D&&) = delete; + + /** + * Disallows the copy assignment operator. + */ + Servo2D& operator=(const Servo2D&) = delete; + + /** + * Disallows the move assignment operator. + */ + Servo2D& operator=(Servo2D&&) = delete; + +protected: + /** + * Initializes the Landscape Application. + * @return - 0 on success, error code on failure. + */ + int init() override; + + /** + * Deinitializes the Landscape Application. + * @return - 0 on success, error code on failure. + */ + int deInit() override; + + /** + * Returns the size of the Prism, default = +/- (1.0f, 1.0f, 1.0f) meters. + * Used in createPrism(). + */ + const glm::vec3 getInitialPrismExtents() const; + + /** + * Creates the prism, updates the private variable prism_ with the created prism. + */ + int createInitialPrism(); + + /** + * Initializes and creates the scene of all scenes marked as initially instanced + */ + void instanceInitialScenes(); + + /** + * Initializes and creates the scene of the scene and instances it into the prism + */ + lumin::Node* instanceScene(const SceneDescriptor & sceneToInit); + + /** + * Run application login + */ + virtual bool updateLoop(float fDelta) override; + + /** + * Handle events from the server + */ + virtual bool eventListener(lumin::ServerEvent* event) override; + bool touchpadEventListener(lumin::ControlTouchPadInputEventData* event); + bool keyEventListener(lumin::KeyInputEventData* event); + + /** + * Get the current cursor position, with respect to the viewport. + */ + glm::vec2 viewportCursorPosition(); + bool pointInsideViewport(glm::vec2 pt); + +private: + lumin::Prism* prism_ = nullptr; // represents the bounded space where the App renders. + lumin::PlanarResource* plane_ = nullptr; // the plane we're rendering into + lumin::QuadNode* content_node_ = nullptr; // the node containing the plane + ServoInstance servo_ = nullptr; // the servo instance we're embedding +}; diff --git a/support/magicleap/Servo2D/code/src.gen/SceneDescriptor.cpp b/support/magicleap/Servo2D/code/src.gen/SceneDescriptor.cpp new file mode 100644 index 00000000000..08bb47d61ac --- /dev/null +++ b/support/magicleap/Servo2D/code/src.gen/SceneDescriptor.cpp @@ -0,0 +1,54 @@ +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- +// +// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND +// ANY MODIFICATIONS WILL BE OVERWRITTEN +// +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- + +// %BANNER_BEGIN% +// --------------------------------------------------------------------- +// %COPYRIGHT_BEGIN% +// +// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved. +// Use of this file is governed by the Creator Agreement, located +// here: https://id.magicleap.com/creator-terms +// +// %COPYRIGHT_END% +// --------------------------------------------------------------------- +// %BANNER_END% + +#include <SceneDescriptor.h> + +SceneDescriptor::SceneDescriptor(const char * exportedName, const char * id, const char * sceneGraphPath, const char * resourceModelPath, const ExportedNodeReferences& exportedNodeReferences, bool initiallyInstanced) +: + exportedName_(exportedName), + id_(id), + sceneGraphPath_(sceneGraphPath), + resourceModelPath_(resourceModelPath), + exportedNodeReferences_(exportedNodeReferences), + initiallyInstanced_(initiallyInstanced) { +} + +const std::string & SceneDescriptor::getExportedName() const { + return exportedName_; +} + +const std::string & SceneDescriptor::getId() const { + return id_; +} + +const std::string & SceneDescriptor::getSceneGraphPath() const { + return sceneGraphPath_; +} + +const std::string & SceneDescriptor::getResourceModelPath() const { + return resourceModelPath_; +} + +const SceneDescriptor::ExportedNodeReferences & SceneDescriptor::getExportedNodeReferences() const { + return exportedNodeReferences_; +} + +bool SceneDescriptor::getInitiallyInstanced() const { + return initiallyInstanced_; +} diff --git a/support/magicleap/Servo2D/code/src.gen/scenesGen.cpp b/support/magicleap/Servo2D/code/src.gen/scenesGen.cpp new file mode 100644 index 00000000000..6c40880be9e --- /dev/null +++ b/support/magicleap/Servo2D/code/src.gen/scenesGen.cpp @@ -0,0 +1,49 @@ +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- +// +// THE CONTENTS OF THIS FILE IS GENERATED BY CODE AND +// ANY MODIFICATIONS WILL BE OVERWRITTEN +// +// -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- + +// %BANNER_BEGIN% +// --------------------------------------------------------------------- +// %COPYRIGHT_BEGIN% +// +// Copyright (c) 2018 Magic Leap, Inc. All Rights Reserved. +// Use of this file is governed by the Creator Agreement, located +// here: https://id.magicleap.com/creator-terms +// +// %COPYRIGHT_END% +// --------------------------------------------------------------------- +// %BANNER_END% + +#include <scenesGen.h> + +namespace Servo2D_exportedNodes { + const std::string content = "content"; + const std::string backButton = "backButton"; + const std::string fwdButton = "fwdButton"; + const std::string urlBar = "urlBar"; +} + +namespace scenes { + + const SceneDescriptor::ExportedNodeReferences Servo2D_exportedNodesMap = { + {"content", Servo2D_exportedNodes::content}, + {"backButton", Servo2D_exportedNodes::backButton}, + {"fwdButton", Servo2D_exportedNodes::fwdButton}, + {"urlBar", Servo2D_exportedNodes::urlBar} + }; + + const SceneDescriptor Servo2D( + "Servo2D", + "root", + "/assets/scenes/scenes/Servo2D.scene.xml", + "/assets/scenes/scenes/Servo2D.scene.res.xml", + Servo2D_exportedNodesMap, + true); + + const SceneDescriptorReferences exportedScenes = { + {Servo2D.getExportedName(), Servo2D} + }; +} diff --git a/support/magicleap/Servo2D/code/src/Servo2D.cpp b/support/magicleap/Servo2D/code/src/Servo2D.cpp new file mode 100644 index 00000000000..8704478e210 --- /dev/null +++ b/support/magicleap/Servo2D/code/src/Servo2D.cpp @@ -0,0 +1,264 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <Servo2D.h> +#include <lumin/node/RootNode.h> +#include <lumin/node/QuadNode.h> +#include <lumin/ui/Cursor.h> +#include <ml_logging.h> +#include <scenesGen.h> +#include <SceneDescriptor.h> +#include <EGL/egl.h> +#include <GLES/gl.h> +#include <glm/gtc/matrix_transform.hpp> +#include <string.h> + +// The viewport dimensions (in px). +const int VIEWPORT_W = 500; +const int VIEWPORT_H = 500; + +// The hidpi factor. +const float HIDPI = 1.0; + +// The prism dimensions (in m). +const float PRISM_W = 0.5; +const float PRISM_H = 0.5; +const float PRISM_D = 0.5; + +// A function which calls the ML logger, suitable for passing into Servo +typedef void (*MLLogger)(MLLogLevel lvl, char* msg); +void logger(MLLogLevel lvl, char* msg) { + if (MLLoggingLogLevelIsEnabled(lvl)) { + MLLoggingLog(lvl, ML_DEFAULT_LOG_TAG, msg); + } +} + +// The functions Servo provides for hooking up to the ML. +// For the moment, this doesn't handle input events. +extern "C" ServoInstance init_servo(EGLContext, EGLSurface, EGLDisplay, MLLogger, + const char* url, int width, int height, float hidpi); +extern "C" void heartbeat_servo(ServoInstance); +extern "C" void cursor_servo(ServoInstance, float x, float y, bool triggered); +extern "C" void discard_servo(ServoInstance); + +// Create a Servo2D instance +Servo2D::Servo2D() { + ML_LOG(Debug, "Servo2D Constructor."); +} + +// Destroy a Servo 2D instance +Servo2D::~Servo2D() { + ML_LOG(Debug, "Servo2D Destructor."); + discard_servo(servo_); + servo_ = nullptr; +} + +// The prism dimensions +const glm::vec3 Servo2D::getInitialPrismExtents() const { + return glm::vec3(PRISM_W, PRISM_H, PRISM_D); +} + +// Create the prism for Servo +int Servo2D::createInitialPrism() { + prism_ = requestNewPrism(getInitialPrismExtents()); + if (!prism_) { + ML_LOG(Error, "Servo2D Error creating default prism."); + return 1; + } + return 0; +} + +// Initialize a Servo instance +int Servo2D::init() { + + ML_LOG(Debug, "Servo2D Initializing."); + + // Set up the prism + createInitialPrism(); + lumin::ui::Cursor::SetScale(prism_, 0.03f); + instanceInitialScenes(); + + // Get the planar resource that holds the EGL context + lumin::RootNode* root_node = prism_->getRootNode(); + if (!root_node) { + ML_LOG(Error, "Servo2D Failed to get root node"); + abort(); + return 1; + } + + std::string content_node_id = Servo2D_exportedNodes::content; + content_node_ = lumin::QuadNode::CastFrom(prism_->findNode(content_node_id, root_node)); + if (!content_node_) { + ML_LOG(Error, "Servo2D Failed to get content node"); + abort(); + return 1; + } + content_node_->setTriggerable(true); + + lumin::ResourceIDType plane_id = prism_->createPlanarEGLResourceId(); + if (!plane_id) { + ML_LOG(Error, "Servo2D Failed to create EGL resource"); + abort(); + return 1; + } + + plane_ = static_cast<lumin::PlanarResource*>(prism_->getResource(plane_id)); + if (!plane_) { + ML_LOG(Error, "Servo2D Failed to create plane"); + abort(); + return 1; + } + + content_node_->setRenderResource(plane_id); + + // Get the EGL context, surface and display. + EGLContext ctx = plane_->getEGLContext(); + EGLSurface surf = plane_->getEGLSurface(); + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglMakeCurrent(dpy, surf, surf, ctx); + glViewport(0, 0, VIEWPORT_W, VIEWPORT_H); + + // Hook into servo + servo_ = init_servo(ctx, surf, dpy, logger, "https://servo.org/", VIEWPORT_H, VIEWPORT_W, HIDPI); + if (!servo_) { + ML_LOG(Error, "Servo2D Failed to init servo instance"); + abort(); + return 1; + } + + // Flush GL + glFlush(); + eglSwapBuffers(dpy, surf); + return 0; +} + +int Servo2D::deInit() { + ML_LOG(Debug, "Servo2D Deinitializing."); + return 0; +} + +lumin::Node* Servo2D::instanceScene(const SceneDescriptor& scene) { + // Load resources. + if (!prism_->loadResourceModel(scene.getResourceModelPath())) { + ML_LOG(Info, "No resource model loaded"); + } + + // Load a scene file. + std::string editorObjectModelName; + if (!prism_->loadObjectModel(scene.getSceneGraphPath(), editorObjectModelName)) { + ML_LOG(Error, "Servo2D Failed to load object model"); + abort(); + return nullptr; + } + + // Add scene to this prism. + lumin::Node* newTree = prism_->createAll(editorObjectModelName); + if (!prism_->getRootNode()->addChild(newTree)) { + ML_LOG(Error, "Servo2D Failed to add newTree to the prism root node"); + abort(); + return nullptr; + } + + return newTree; +} + +void Servo2D::instanceInitialScenes() { + // Iterate over all the exported scenes + for (auto& exportedSceneEntry : scenes::exportedScenes ) { + + // If this scene was marked to be instanced at app initialization, do it + const SceneDescriptor &sd = exportedSceneEntry.second; + if (sd.getInitiallyInstanced()) { + instanceScene(sd); + } + } +} + +bool Servo2D::updateLoop(float fDelta) { + // Get the EGL context, surface and display. + EGLContext ctx = plane_->getEGLContext(); + EGLSurface surf = plane_->getEGLSurface(); + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglMakeCurrent(dpy, surf, surf, ctx); + glViewport(0, 0, VIEWPORT_W, VIEWPORT_H); + + // Hook into servo + heartbeat_servo(servo_); + + // Flush GL + glFlush(); + eglSwapBuffers(dpy, surf); + + // Return true for your app to continue running, false to terminate the app. + return true; +} + +bool Servo2D::eventListener(lumin::ServerEvent* event) { + // Dispatch based on event type + switch (event->getServerEventType()) { + case lumin::ServerEventType::kControlTouchPadInputEvent: + return touchpadEventListener(static_cast<lumin::ControlTouchPadInputEventData*>(event)); + case lumin::ServerEventType::kKeyInputEvent: + return keyEventListener(static_cast<lumin::KeyInputEventData*>(event)); + default: + return false; + } +} + +glm::vec2 Servo2D::viewportCursorPosition() { + // Get the cursor position relative to the origin of the content node (in m) + glm::vec3 pos = lumin::ui::Cursor::GetPosition(prism_) - content_node_->getPrismPosition(); + + // Get the size of the content node (in m) + glm::vec2 sz = content_node_->getSize(); + + // Convert to a position in viewport px + float x = (pos.x / sz.x) * (float)VIEWPORT_W; + float y = (1 - pos.y / sz.y) * (float)VIEWPORT_H; // Sigh, invert the y coordinate + + return glm::vec2(x, y); +} + +bool Servo2D::pointInsideViewport(glm::vec2 pt) { + return (0 <= pt.x && 0 <= pt.y && pt.x <= VIEWPORT_W && pt.y <= VIEWPORT_H); +} + +bool Servo2D::touchpadEventListener(lumin::ControlTouchPadInputEventData* event) { + // Only respond when the cursor is enabled + if (!lumin::ui::Cursor::IsEnabled(prism_)) { + return false; + } + + // Only respond when the cursor is inside the viewport + glm::vec2 pos = viewportCursorPosition(); + if (!pointInsideViewport(pos)) { + return false; + } + + // Inform Servo of the trigger + cursor_servo(servo_, pos.x, pos.y, false); + return true; +} + +bool Servo2D::keyEventListener(lumin::KeyInputEventData* event) { + // Only respond to trigger keys + if (event->keyCode() != lumin::input::KeyCodes::AKEYCODE_EX_TRIGGER) { + return false; + } + + // Only respond when the cursor is enabled + if (!lumin::ui::Cursor::IsEnabled(prism_)) { + return false; + } + + // Only respond when the cursor is inside the viewport + glm::vec2 pos = viewportCursorPosition(); + if (!pointInsideViewport(pos)) { + return false; + } + + // Inform Servo of the trigger + cursor_servo(servo_, pos.x, pos.y, true); + return true; +} diff --git a/support/magicleap/Servo2D/code/src/main.cpp b/support/magicleap/Servo2D/code/src/main.cpp new file mode 100644 index 00000000000..d8abed18c34 --- /dev/null +++ b/support/magicleap/Servo2D/code/src/main.cpp @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <Servo2D.h> +#include <ml_logging.h> + +int main(int argc, char **argv) +{ + ML_LOG(Debug, "Servo2D Starting."); + Servo2D myApp; + return myApp.run(); +} diff --git a/support/magicleap/Servo2D/code/srcsGen.comp b/support/magicleap/Servo2D/code/srcsGen.comp new file mode 100644 index 00000000000..d46daea0bbb --- /dev/null +++ b/support/magicleap/Servo2D/code/srcsGen.comp @@ -0,0 +1,3 @@ +SRCS = \ + src.gen/scenesGen.cpp \ + src.gen/SceneDescriptor.cpp \ |