aboutsummaryrefslogtreecommitdiffstats
path: root/support/magicleap/Servo2D/code
diff options
context:
space:
mode:
Diffstat (limited to 'support/magicleap/Servo2D/code')
-rw-r--r--support/magicleap/Servo2D/code/inc.gen/SceneDescriptor.h48
-rw-r--r--support/magicleap/Servo2D/code/inc.gen/scenesGen.h34
-rw-r--r--support/magicleap/Servo2D/code/inc/Servo2D.h108
-rw-r--r--support/magicleap/Servo2D/code/src.gen/SceneDescriptor.cpp54
-rw-r--r--support/magicleap/Servo2D/code/src.gen/scenesGen.cpp49
-rw-r--r--support/magicleap/Servo2D/code/src/Servo2D.cpp264
-rw-r--r--support/magicleap/Servo2D/code/src/main.cpp13
-rw-r--r--support/magicleap/Servo2D/code/srcsGen.comp3
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 \