summaryrefslogtreecommitdiff
path: root/platform/nacl/godot_module.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/nacl/godot_module.cpp')
-rw-r--r--platform/nacl/godot_module.cpp332
1 files changed, 332 insertions, 0 deletions
diff --git a/platform/nacl/godot_module.cpp b/platform/nacl/godot_module.cpp
new file mode 100644
index 0000000000..b5a049d9bf
--- /dev/null
+++ b/platform/nacl/godot_module.cpp
@@ -0,0 +1,332 @@
+/*************************************************************************/
+/* godot_module.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "opengl_context.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/gles2/gl2ext_ppapi.h"
+
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+#include "ppapi/cpp/var.h"
+#include "geturl_handler.h"
+
+#include "core/variant.h"
+#include "os_nacl.h"
+
+extern int nacl_main(int argc, const char** argn, const char** argv);
+extern void nacl_cleanup();
+
+static String pkg_url;
+
+pp::Instance* godot_instance = NULL;
+
+struct StateData {
+ int arg_count;
+ Array args;
+ String method;
+};
+
+extern OSNacl* os_nacl;
+
+class GodotInstance : public pp::Instance {
+
+ enum State {
+ STATE_METHOD,
+ STATE_PARAM_COUNT,
+ STATE_PARAMS,
+ STATE_CALL,
+ };
+
+ State state;
+ StateData* sd;
+ SharedOpenGLContext opengl_context_;
+ int width;
+ int height;
+
+ #define MAX_ARGS 64
+ uint32_t init_argc;
+ char* init_argn[MAX_ARGS];
+ char* init_argv[MAX_ARGS];
+
+ bool package_loaded;
+ GetURLHandler* package_pending;
+
+public:
+ explicit GodotInstance(PP_Instance instance) : pp::Instance(instance) {
+ printf("GodotInstance!\n");
+ state = STATE_METHOD;
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_KEYBOARD | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_TOUCH);
+ sd = NULL;
+ package_pending = NULL;
+ package_loaded = false;
+ godot_instance = this;
+ }
+ virtual ~GodotInstance() {
+
+ nacl_cleanup();
+ }
+
+ /// Called by the browser to handle the postMessage() call in Javascript.
+ /// Detects which method is being called from the message contents, and
+ /// calls the appropriate function. Posts the result back to the browser
+ /// asynchronously.
+ /// @param[in] var_message The message posted by the browser. The possible
+ /// messages are 'fortyTwo' and 'reverseText:Hello World'. Note that
+ /// the 'reverseText' form contains the string to reverse following a ':'
+ /// separator.
+ virtual void HandleMessage(const pp::Var& var_message);
+
+ bool HandleInputEvent(const pp::InputEvent& event);
+
+ bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
+
+ printf("******* init! %i, %p, %p\n", argc, argn, argv);
+ fflush(stdout);
+ if (opengl_context_ == NULL) {
+ opengl_context_.reset(new OpenGLContext(this));
+ };
+ opengl_context_->InvalidateContext(this);
+ opengl_context_->ResizeContext(pp::Size(0, 0));
+ int current = opengl_context_->MakeContextCurrent(this);
+ printf("current is %i\n", current);
+
+ os_nacl = new OSNacl;
+
+ pkg_url = "";
+ for (uint32_t i=0; i<argc; i++) {
+ if (strcmp(argn[i], "package") == 0) {
+ pkg_url = argv[i];
+ };
+ };
+
+ sd = memnew(StateData);
+
+ if (pkg_url == "") {
+ nacl_main(argc, argn, argv);
+ } else {
+ printf("starting package %ls\n", pkg_url.c_str());
+ init_argc = MIN(argc, MAX_ARGS-1);
+ for (uint32_t i=0; i<argc; i++) {
+
+ int nlen = strlen(argn[i]);
+ init_argn[i] = (char*)memalloc(nlen+1);
+ strcpy(init_argn[i], argn[i]);
+ init_argn[i+1] = NULL;
+
+ int len = strlen(argv[i]);
+ init_argv[i] = (char*)memalloc(len+1);
+ strcpy(init_argv[i], argv[i]);
+ init_argv[i+1] = NULL;
+ };
+ package_pending = memnew(GetURLHandler(this, pkg_url));
+ package_pending->Start();
+ };
+ return true;
+ };
+
+ // Called whenever the in-browser window changes size.
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
+
+ if (position.size().width() == width &&
+ position.size().height() == height)
+ return; // Size didn't change, no need to update anything.
+
+ if (opengl_context_ == NULL) {
+ opengl_context_.reset(new OpenGLContext(this));
+ };
+ opengl_context_->InvalidateContext(this);
+ opengl_context_->ResizeContext(position.size());
+ if (!opengl_context_->MakeContextCurrent(this))
+ return;
+
+ width = position.size().width();
+ height = position.size().height();
+ // init gl here?
+ OS::VideoMode vm;
+ vm.width = width;
+ vm.height = height;
+ vm.resizable = false;
+ vm.fullscreen = true;
+ OS::get_singleton()->set_video_mode(vm, 0);
+
+ DrawSelf();
+ };
+
+ // Called to draw the contents of the module's browser area.
+ void DrawSelf() {
+
+ if (opengl_context_ == NULL)
+ return;
+
+ opengl_context_->FlushContext();
+ };
+};
+
+static Variant to_variant(const pp::Var& p_var) {
+
+ if (p_var.is_undefined() || p_var.is_null())
+ return Variant();
+ if (p_var.is_bool())
+ return Variant(p_var.AsBool());
+ if (p_var.is_double())
+ return Variant(p_var.AsDouble());
+ if (p_var.is_int())
+ return Variant((int64_t)p_var.AsInt());
+ if (p_var.is_string())
+ return Variant(String::utf8(p_var.AsString().c_str()));
+
+ return Variant();
+};
+
+void GodotInstance::HandleMessage(const pp::Var& var_message) {
+
+ switch (state) {
+
+ case STATE_METHOD: {
+
+ ERR_FAIL_COND(!var_message.is_string());
+ sd->method = var_message.AsString().c_str();
+ state = STATE_PARAM_COUNT;
+ } break;
+ case STATE_PARAM_COUNT: {
+
+ ERR_FAIL_COND(!var_message.is_number());
+ sd->arg_count = var_message.AsInt();
+ state = sd->arg_count>0?STATE_PARAMS:STATE_CALL;
+
+ } break;
+ case STATE_PARAMS: {
+
+ Variant p = to_variant(var_message);
+ sd->args.push_back(p);
+ if (sd->args.size() >= sd->arg_count)
+ state = STATE_CALL;
+ } break;
+ default:
+ break;
+ };
+
+ if (state == STATE_CALL) {
+
+ // call
+ state = STATE_METHOD;
+
+
+ if (sd->method == "package_finished") {
+
+ GetURLHandler::Status status = package_pending->get_status();
+ printf("status is %i, %i, %i\n", status, GetURLHandler::STATUS_ERROR, GetURLHandler::STATUS_COMPLETED);
+ if (status == GetURLHandler::STATUS_ERROR) {
+ printf("Error fetching package!\n");
+ };
+ if (status == GetURLHandler::STATUS_COMPLETED) {
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ os->add_package(pkg_url, package_pending->get_data());
+ };
+ memdelete(package_pending);
+ package_pending = NULL;
+
+ package_loaded = true;
+
+ opengl_context_->MakeContextCurrent(this);
+ nacl_main(init_argc, (const char**)init_argn, (const char**)init_argv);
+ for (uint32_t i=0; i<init_argc; i++) {
+ memfree(init_argn[i]);
+ memfree(init_argv[i]);
+ };
+ };
+
+ if (sd->method == "get_package_status") {
+
+ if (package_loaded) {
+ // post "loaded"
+ PostMessage("loaded");
+ } else if (package_pending == NULL) {
+ // post "none"
+ PostMessage("none");
+ } else {
+ // post package_pending->get_bytes_read();
+ PostMessage(package_pending->get_bytes_read());
+ };
+ };
+ };
+}
+
+bool GodotInstance::HandleInputEvent(const pp::InputEvent& event) {
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ os->handle_event(event);
+ return true;
+};
+
+class GodotModule : public pp::Module {
+ public:
+ GodotModule() : pp::Module() {}
+ virtual ~GodotModule() {
+ glTerminatePPAPI();
+ }
+
+ /// Create and return a GodotInstance object.
+ /// @param[in] instance a handle to a plug-in instance.
+ /// @return a newly created GodotInstance.
+ /// @note The browser is responsible for calling @a delete when done.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ printf("CreateInstance! %x\n", instance);
+ return new GodotInstance(instance);
+ }
+
+ /// Called by the browser when the module is first loaded and ready to run.
+ /// This is called once per module, not once per instance of the module on
+ /// the page.
+ virtual bool Init() {
+ printf("GodotModule::init!\n");
+ return glInitializePPAPI(get_browser_interface());
+ }
+};
+
+namespace pp {
+/// Factory function called by the browser when the module is first loaded.
+/// The browser keeps a singleton of this module. It calls the
+/// CreateInstance() method on the object you return to make instances. There
+/// is one instance per <embed> tag on the page. This is the main binding
+/// point for your NaCl module with the browser.
+/// @return new GodotModule.
+/// @note The browser is responsible for deleting returned @a Module.
+Module* CreateModule() {
+ printf("CreateModule!\n");
+ return new GodotModule();
+}
+} // namespace pp