/*************************************************************************/ /* 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 #include #include #include #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; iStart(); }; 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; imethod == "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 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